Merge branch 'synaptics-rmi4' into next
Merge updated Synaptics RMI4 support, including support for SMBus controllers and flashing firmware.
This commit is contained in:
@@ -396,9 +396,13 @@ locations and some common work such as cleanup has to be done. If there is no
|
|||||||
cleanup needed then just return directly.
|
cleanup needed then just return directly.
|
||||||
|
|
||||||
Choose label names which say what the goto does or why the goto exists. An
|
Choose label names which say what the goto does or why the goto exists. An
|
||||||
example of a good name could be "out_buffer:" if the goto frees "buffer". Avoid
|
example of a good name could be "out_free_buffer:" if the goto frees "buffer".
|
||||||
using GW-BASIC names like "err1:" and "err2:". Also don't name them after the
|
Avoid using GW-BASIC names like "err1:" and "err2:", as you would have to
|
||||||
goto location like "err_kmalloc_failed:"
|
renumber them if you ever add or remove exit paths, and they make correctness
|
||||||
|
difficult to verify anyway.
|
||||||
|
|
||||||
|
It is advised to indent labels with a single space (not tab), so that
|
||||||
|
"diff -p" does not confuse labels with functions.
|
||||||
|
|
||||||
The rationale for using gotos is:
|
The rationale for using gotos is:
|
||||||
|
|
||||||
@@ -425,7 +429,7 @@ The rationale for using gotos is:
|
|||||||
goto out_buffer;
|
goto out_buffer;
|
||||||
}
|
}
|
||||||
...
|
...
|
||||||
out_buffer:
|
out_free_buffer:
|
||||||
kfree(buffer);
|
kfree(buffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -438,7 +442,16 @@ A common type of bug to be aware of is "one err bugs" which look like this:
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
The bug in this code is that on some exit paths "foo" is NULL. Normally the
|
The bug in this code is that on some exit paths "foo" is NULL. Normally the
|
||||||
fix for this is to split it up into two error labels "err_bar:" and "err_foo:".
|
fix for this is to split it up into two error labels "err_free_bar:" and
|
||||||
|
"err_free_foo:":
|
||||||
|
|
||||||
|
err_free_bar:
|
||||||
|
kfree(foo->bar);
|
||||||
|
err_free_foo:
|
||||||
|
kfree(foo);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
Ideally you should simulate errors to test all exit paths.
|
||||||
|
|
||||||
|
|
||||||
Chapter 8: Commenting
|
Chapter 8: Commenting
|
||||||
@@ -461,9 +474,6 @@ When commenting the kernel API functions, please use the kernel-doc format.
|
|||||||
See the files Documentation/kernel-documentation.rst and scripts/kernel-doc
|
See the files Documentation/kernel-documentation.rst and scripts/kernel-doc
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
Linux style for comments is the C89 "/* ... */" style.
|
|
||||||
Don't use C99-style "// ..." comments.
|
|
||||||
|
|
||||||
The preferred style for long (multi-line) comments is:
|
The preferred style for long (multi-line) comments is:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -931,10 +931,8 @@ to "Closing".
|
|||||||
|
|
||||||
1) Struct scatterlist requirements.
|
1) Struct scatterlist requirements.
|
||||||
|
|
||||||
Don't invent the architecture specific struct scatterlist; just use
|
You need to enable CONFIG_NEED_SG_DMA_LENGTH if the architecture
|
||||||
<asm-generic/scatterlist.h>. You need to enable
|
supports IOMMUs (including software IOMMU).
|
||||||
CONFIG_NEED_SG_DMA_LENGTH if the architecture supports IOMMUs
|
|
||||||
(including software IOMMU).
|
|
||||||
|
|
||||||
2) ARCH_DMA_MINALIGN
|
2) ARCH_DMA_MINALIGN
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
# To add a new book the only step required is to add the book to the
|
# To add a new book the only step required is to add the book to the
|
||||||
# list of DOCBOOKS.
|
# list of DOCBOOKS.
|
||||||
|
|
||||||
DOCBOOKS := z8530book.xml device-drivers.xml \
|
DOCBOOKS := z8530book.xml \
|
||||||
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
|
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
|
||||||
writing_usb_driver.xml networking.xml \
|
writing_usb_driver.xml networking.xml \
|
||||||
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
||||||
@@ -22,8 +22,14 @@ ifeq ($(DOCBOOKS),)
|
|||||||
# Skip DocBook build if the user explicitly requested no DOCBOOKS.
|
# Skip DocBook build if the user explicitly requested no DOCBOOKS.
|
||||||
.DEFAULT:
|
.DEFAULT:
|
||||||
@echo " SKIP DocBook $@ target (DOCBOOKS=\"\" specified)."
|
@echo " SKIP DocBook $@ target (DOCBOOKS=\"\" specified)."
|
||||||
|
|
||||||
else
|
else
|
||||||
|
ifneq ($(SPHINXDIRS),)
|
||||||
|
|
||||||
|
# Skip DocBook build if the user explicitly requested a sphinx dir
|
||||||
|
.DEFAULT:
|
||||||
|
@echo " SKIP DocBook $@ target (SPHINXDIRS specified)."
|
||||||
|
else
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# The build process is as follows (targets):
|
# The build process is as follows (targets):
|
||||||
@@ -66,6 +72,7 @@ installmandocs: mandocs
|
|||||||
|
|
||||||
# no-op for the DocBook toolchain
|
# no-op for the DocBook toolchain
|
||||||
epubdocs:
|
epubdocs:
|
||||||
|
latexdocs:
|
||||||
|
|
||||||
###
|
###
|
||||||
#External programs used
|
#External programs used
|
||||||
@@ -221,6 +228,7 @@ silent_gen_xml = :
|
|||||||
echo "</programlisting>") > $@
|
echo "</programlisting>") > $@
|
||||||
|
|
||||||
endif # DOCBOOKS=""
|
endif # DOCBOOKS=""
|
||||||
|
endif # SPHINDIR=...
|
||||||
|
|
||||||
###
|
###
|
||||||
# Help targets as used by the top-level makefile
|
# Help targets as used by the top-level makefile
|
||||||
|
@@ -1,521 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
|
||||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
|
||||||
|
|
||||||
<book id="LinuxDriversAPI">
|
|
||||||
<bookinfo>
|
|
||||||
<title>Linux Device Drivers</title>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>
|
|
||||||
This documentation is free software; you can redistribute
|
|
||||||
it and/or modify it under the terms of the GNU General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This program is distributed in the hope that it will be
|
|
||||||
useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
||||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
See the GNU General Public License for more details.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You should have received a copy of the GNU General Public
|
|
||||||
License along with this program; if not, write to the Free
|
|
||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
||||||
MA 02111-1307 USA
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
For more details see the file COPYING in the source
|
|
||||||
distribution of Linux.
|
|
||||||
</para>
|
|
||||||
</legalnotice>
|
|
||||||
</bookinfo>
|
|
||||||
|
|
||||||
<toc></toc>
|
|
||||||
|
|
||||||
<chapter id="Basics">
|
|
||||||
<title>Driver Basics</title>
|
|
||||||
<sect1><title>Driver Entry and Exit points</title>
|
|
||||||
!Iinclude/linux/init.h
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1><title>Atomic and pointer manipulation</title>
|
|
||||||
!Iarch/x86/include/asm/atomic.h
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1><title>Delaying, scheduling, and timer routines</title>
|
|
||||||
!Iinclude/linux/sched.h
|
|
||||||
!Ekernel/sched/core.c
|
|
||||||
!Ikernel/sched/cpupri.c
|
|
||||||
!Ikernel/sched/fair.c
|
|
||||||
!Iinclude/linux/completion.h
|
|
||||||
!Ekernel/time/timer.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Wait queues and Wake events</title>
|
|
||||||
!Iinclude/linux/wait.h
|
|
||||||
!Ekernel/sched/wait.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>High-resolution timers</title>
|
|
||||||
!Iinclude/linux/ktime.h
|
|
||||||
!Iinclude/linux/hrtimer.h
|
|
||||||
!Ekernel/time/hrtimer.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Workqueues and Kevents</title>
|
|
||||||
!Iinclude/linux/workqueue.h
|
|
||||||
!Ekernel/workqueue.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Internal Functions</title>
|
|
||||||
!Ikernel/exit.c
|
|
||||||
!Ikernel/signal.c
|
|
||||||
!Iinclude/linux/kthread.h
|
|
||||||
!Ekernel/kthread.c
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1><title>Kernel objects manipulation</title>
|
|
||||||
<!--
|
|
||||||
X!Iinclude/linux/kobject.h
|
|
||||||
-->
|
|
||||||
!Elib/kobject.c
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1><title>Kernel utility functions</title>
|
|
||||||
!Iinclude/linux/kernel.h
|
|
||||||
!Ekernel/printk/printk.c
|
|
||||||
!Ekernel/panic.c
|
|
||||||
!Ekernel/sys.c
|
|
||||||
!Ekernel/rcu/srcu.c
|
|
||||||
!Ekernel/rcu/tree.c
|
|
||||||
!Ekernel/rcu/tree_plugin.h
|
|
||||||
!Ekernel/rcu/update.c
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1><title>Device Resource Management</title>
|
|
||||||
!Edrivers/base/devres.c
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="devdrivers">
|
|
||||||
<title>Device drivers infrastructure</title>
|
|
||||||
<sect1><title>The Basic Device Driver-Model Structures </title>
|
|
||||||
!Iinclude/linux/device.h
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Device Drivers Base</title>
|
|
||||||
!Idrivers/base/init.c
|
|
||||||
!Edrivers/base/driver.c
|
|
||||||
!Edrivers/base/core.c
|
|
||||||
!Edrivers/base/syscore.c
|
|
||||||
!Edrivers/base/class.c
|
|
||||||
!Idrivers/base/node.c
|
|
||||||
!Edrivers/base/firmware_class.c
|
|
||||||
!Edrivers/base/transport_class.c
|
|
||||||
<!-- Cannot be included, because
|
|
||||||
attribute_container_add_class_device_adapter
|
|
||||||
and attribute_container_classdev_to_container
|
|
||||||
exceed allowed 44 characters maximum
|
|
||||||
X!Edrivers/base/attribute_container.c
|
|
||||||
-->
|
|
||||||
!Edrivers/base/dd.c
|
|
||||||
<!--
|
|
||||||
X!Edrivers/base/interface.c
|
|
||||||
-->
|
|
||||||
!Iinclude/linux/platform_device.h
|
|
||||||
!Edrivers/base/platform.c
|
|
||||||
!Edrivers/base/bus.c
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>Buffer Sharing and Synchronization</title>
|
|
||||||
<para>
|
|
||||||
The dma-buf subsystem provides the framework for sharing buffers
|
|
||||||
for hardware (DMA) access across multiple device drivers and
|
|
||||||
subsystems, and for synchronizing asynchronous hardware access.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This is used, for example, by drm "prime" multi-GPU support, but
|
|
||||||
is of course not limited to GPU use cases.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The three main components of this are: (1) dma-buf, representing
|
|
||||||
a sg_table and exposed to userspace as a file descriptor to allow
|
|
||||||
passing between devices, (2) fence, which provides a mechanism
|
|
||||||
to signal when one device as finished access, and (3) reservation,
|
|
||||||
which manages the shared or exclusive fence(s) associated with
|
|
||||||
the buffer.
|
|
||||||
</para>
|
|
||||||
<sect2><title>dma-buf</title>
|
|
||||||
!Edrivers/dma-buf/dma-buf.c
|
|
||||||
!Iinclude/linux/dma-buf.h
|
|
||||||
</sect2>
|
|
||||||
<sect2><title>reservation</title>
|
|
||||||
!Pdrivers/dma-buf/reservation.c Reservation Object Overview
|
|
||||||
!Edrivers/dma-buf/reservation.c
|
|
||||||
!Iinclude/linux/reservation.h
|
|
||||||
</sect2>
|
|
||||||
<sect2><title>fence</title>
|
|
||||||
!Edrivers/dma-buf/fence.c
|
|
||||||
!Iinclude/linux/fence.h
|
|
||||||
!Edrivers/dma-buf/seqno-fence.c
|
|
||||||
!Iinclude/linux/seqno-fence.h
|
|
||||||
!Edrivers/dma-buf/fence-array.c
|
|
||||||
!Iinclude/linux/fence-array.h
|
|
||||||
!Edrivers/dma-buf/reservation.c
|
|
||||||
!Iinclude/linux/reservation.h
|
|
||||||
!Edrivers/dma-buf/sync_file.c
|
|
||||||
!Iinclude/linux/sync_file.h
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Device Drivers DMA Management</title>
|
|
||||||
!Edrivers/base/dma-coherent.c
|
|
||||||
!Edrivers/base/dma-mapping.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Device Drivers Power Management</title>
|
|
||||||
!Edrivers/base/power/main.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Device Drivers ACPI Support</title>
|
|
||||||
<!-- Internal functions only
|
|
||||||
X!Edrivers/acpi/sleep/main.c
|
|
||||||
X!Edrivers/acpi/sleep/wakeup.c
|
|
||||||
X!Edrivers/acpi/motherboard.c
|
|
||||||
X!Edrivers/acpi/bus.c
|
|
||||||
-->
|
|
||||||
!Edrivers/acpi/scan.c
|
|
||||||
!Idrivers/acpi/scan.c
|
|
||||||
<!-- No correct structured comments
|
|
||||||
X!Edrivers/acpi/pci_bind.c
|
|
||||||
-->
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Device drivers PnP support</title>
|
|
||||||
!Idrivers/pnp/core.c
|
|
||||||
<!-- No correct structured comments
|
|
||||||
X!Edrivers/pnp/system.c
|
|
||||||
-->
|
|
||||||
!Edrivers/pnp/card.c
|
|
||||||
!Idrivers/pnp/driver.c
|
|
||||||
!Edrivers/pnp/manager.c
|
|
||||||
!Edrivers/pnp/support.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Userspace IO devices</title>
|
|
||||||
!Edrivers/uio/uio.c
|
|
||||||
!Iinclude/linux/uio_driver.h
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="parportdev">
|
|
||||||
<title>Parallel Port Devices</title>
|
|
||||||
!Iinclude/linux/parport.h
|
|
||||||
!Edrivers/parport/ieee1284.c
|
|
||||||
!Edrivers/parport/share.c
|
|
||||||
!Idrivers/parport/daisy.c
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="message_devices">
|
|
||||||
<title>Message-based devices</title>
|
|
||||||
<sect1><title>Fusion message devices</title>
|
|
||||||
!Edrivers/message/fusion/mptbase.c
|
|
||||||
!Idrivers/message/fusion/mptbase.c
|
|
||||||
!Edrivers/message/fusion/mptscsih.c
|
|
||||||
!Idrivers/message/fusion/mptscsih.c
|
|
||||||
!Idrivers/message/fusion/mptctl.c
|
|
||||||
!Idrivers/message/fusion/mptspi.c
|
|
||||||
!Idrivers/message/fusion/mptfc.c
|
|
||||||
!Idrivers/message/fusion/mptlan.c
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="snddev">
|
|
||||||
<title>Sound Devices</title>
|
|
||||||
!Iinclude/sound/core.h
|
|
||||||
!Esound/sound_core.c
|
|
||||||
!Iinclude/sound/pcm.h
|
|
||||||
!Esound/core/pcm.c
|
|
||||||
!Esound/core/device.c
|
|
||||||
!Esound/core/info.c
|
|
||||||
!Esound/core/rawmidi.c
|
|
||||||
!Esound/core/sound.c
|
|
||||||
!Esound/core/memory.c
|
|
||||||
!Esound/core/pcm_memory.c
|
|
||||||
!Esound/core/init.c
|
|
||||||
!Esound/core/isadma.c
|
|
||||||
!Esound/core/control.c
|
|
||||||
!Esound/core/pcm_lib.c
|
|
||||||
!Esound/core/hwdep.c
|
|
||||||
!Esound/core/pcm_native.c
|
|
||||||
!Esound/core/memalloc.c
|
|
||||||
<!-- FIXME: Removed for now since no structured comments in source
|
|
||||||
X!Isound/sound_firmware.c
|
|
||||||
-->
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
|
|
||||||
<chapter id="uart16x50">
|
|
||||||
<title>16x50 UART Driver</title>
|
|
||||||
!Edrivers/tty/serial/serial_core.c
|
|
||||||
!Edrivers/tty/serial/8250/8250_core.c
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="fbdev">
|
|
||||||
<title>Frame Buffer Library</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The frame buffer drivers depend heavily on four data structures.
|
|
||||||
These structures are declared in include/linux/fb.h. They are
|
|
||||||
fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs.
|
|
||||||
The last three can be made available to and from userland.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
fb_info defines the current state of a particular video card.
|
|
||||||
Inside fb_info, there exists a fb_ops structure which is a
|
|
||||||
collection of needed functions to make fbdev and fbcon work.
|
|
||||||
fb_info is only visible to the kernel.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
fb_var_screeninfo is used to describe the features of a video card
|
|
||||||
that are user defined. With fb_var_screeninfo, things such as
|
|
||||||
depth and the resolution may be defined.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The next structure is fb_fix_screeninfo. This defines the
|
|
||||||
properties of a card that are created when a mode is set and can't
|
|
||||||
be changed otherwise. A good example of this is the start of the
|
|
||||||
frame buffer memory. This "locks" the address of the frame buffer
|
|
||||||
memory, so that it cannot be changed or moved.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The last structure is fb_monospecs. In the old API, there was
|
|
||||||
little importance for fb_monospecs. This allowed for forbidden things
|
|
||||||
such as setting a mode of 800x600 on a fix frequency monitor. With
|
|
||||||
the new API, fb_monospecs prevents such things, and if used
|
|
||||||
correctly, can prevent a monitor from being cooked. fb_monospecs
|
|
||||||
will not be useful until kernels 2.5.x.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect1><title>Frame Buffer Memory</title>
|
|
||||||
!Edrivers/video/fbdev/core/fbmem.c
|
|
||||||
</sect1>
|
|
||||||
<!--
|
|
||||||
<sect1><title>Frame Buffer Console</title>
|
|
||||||
X!Edrivers/video/console/fbcon.c
|
|
||||||
</sect1>
|
|
||||||
-->
|
|
||||||
<sect1><title>Frame Buffer Colormap</title>
|
|
||||||
!Edrivers/video/fbdev/core/fbcmap.c
|
|
||||||
</sect1>
|
|
||||||
<!-- FIXME:
|
|
||||||
drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment
|
|
||||||
out until somebody adds docs. KAO
|
|
||||||
<sect1><title>Frame Buffer Generic Functions</title>
|
|
||||||
X!Idrivers/video/fbgen.c
|
|
||||||
</sect1>
|
|
||||||
KAO -->
|
|
||||||
<sect1><title>Frame Buffer Video Mode Database</title>
|
|
||||||
!Idrivers/video/fbdev/core/modedb.c
|
|
||||||
!Edrivers/video/fbdev/core/modedb.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Frame Buffer Macintosh Video Mode Database</title>
|
|
||||||
!Edrivers/video/fbdev/macmodes.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Frame Buffer Fonts</title>
|
|
||||||
<para>
|
|
||||||
Refer to the file lib/fonts/fonts.c for more information.
|
|
||||||
</para>
|
|
||||||
<!-- FIXME: Removed for now since no structured comments in source
|
|
||||||
X!Ilib/fonts/fonts.c
|
|
||||||
-->
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="input_subsystem">
|
|
||||||
<title>Input Subsystem</title>
|
|
||||||
<sect1><title>Input core</title>
|
|
||||||
!Iinclude/linux/input.h
|
|
||||||
!Edrivers/input/input.c
|
|
||||||
!Edrivers/input/ff-core.c
|
|
||||||
!Edrivers/input/ff-memless.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Multitouch Library</title>
|
|
||||||
!Iinclude/linux/input/mt.h
|
|
||||||
!Edrivers/input/input-mt.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Polled input devices</title>
|
|
||||||
!Iinclude/linux/input-polldev.h
|
|
||||||
!Edrivers/input/input-polldev.c
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Matrix keyboards/keypads</title>
|
|
||||||
!Iinclude/linux/input/matrix_keypad.h
|
|
||||||
</sect1>
|
|
||||||
<sect1><title>Sparse keymap support</title>
|
|
||||||
!Iinclude/linux/input/sparse-keymap.h
|
|
||||||
!Edrivers/input/sparse-keymap.c
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="spi">
|
|
||||||
<title>Serial Peripheral Interface (SPI)</title>
|
|
||||||
<para>
|
|
||||||
SPI is the "Serial Peripheral Interface", widely used with
|
|
||||||
embedded systems because it is a simple and efficient
|
|
||||||
interface: basically a multiplexed shift register.
|
|
||||||
Its three signal wires hold a clock (SCK, often in the range
|
|
||||||
of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
|
|
||||||
a "Master In, Slave Out" (MISO) data line.
|
|
||||||
SPI is a full duplex protocol; for each bit shifted out the
|
|
||||||
MOSI line (one per clock) another is shifted in on the MISO line.
|
|
||||||
Those bits are assembled into words of various sizes on the
|
|
||||||
way to and from system memory.
|
|
||||||
An additional chipselect line is usually active-low (nCS);
|
|
||||||
four signals are normally used for each peripheral, plus
|
|
||||||
sometimes an interrupt.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The SPI bus facilities listed here provide a generalized
|
|
||||||
interface to declare SPI busses and devices, manage them
|
|
||||||
according to the standard Linux driver model, and perform
|
|
||||||
input/output operations.
|
|
||||||
At this time, only "master" side interfaces are supported,
|
|
||||||
where Linux talks to SPI peripherals and does not implement
|
|
||||||
such a peripheral itself.
|
|
||||||
(Interfaces to support implementing SPI slaves would
|
|
||||||
necessarily look different.)
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The programming interface is structured around two kinds of driver,
|
|
||||||
and two kinds of device.
|
|
||||||
A "Controller Driver" abstracts the controller hardware, which may
|
|
||||||
be as simple as a set of GPIO pins or as complex as a pair of FIFOs
|
|
||||||
connected to dual DMA engines on the other side of the SPI shift
|
|
||||||
register (maximizing throughput). Such drivers bridge between
|
|
||||||
whatever bus they sit on (often the platform bus) and SPI, and
|
|
||||||
expose the SPI side of their device as a
|
|
||||||
<structname>struct spi_master</structname>.
|
|
||||||
SPI devices are children of that master, represented as a
|
|
||||||
<structname>struct spi_device</structname> and manufactured from
|
|
||||||
<structname>struct spi_board_info</structname> descriptors which
|
|
||||||
are usually provided by board-specific initialization code.
|
|
||||||
A <structname>struct spi_driver</structname> is called a
|
|
||||||
"Protocol Driver", and is bound to a spi_device using normal
|
|
||||||
driver model calls.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The I/O model is a set of queued messages. Protocol drivers
|
|
||||||
submit one or more <structname>struct spi_message</structname>
|
|
||||||
objects, which are processed and completed asynchronously.
|
|
||||||
(There are synchronous wrappers, however.) Messages are
|
|
||||||
built from one or more <structname>struct spi_transfer</structname>
|
|
||||||
objects, each of which wraps a full duplex SPI transfer.
|
|
||||||
A variety of protocol tweaking options are needed, because
|
|
||||||
different chips adopt very different policies for how they
|
|
||||||
use the bits transferred with SPI.
|
|
||||||
</para>
|
|
||||||
!Iinclude/linux/spi/spi.h
|
|
||||||
!Fdrivers/spi/spi.c spi_register_board_info
|
|
||||||
!Edrivers/spi/spi.c
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="i2c">
|
|
||||||
<title>I<superscript>2</superscript>C and SMBus Subsystem</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
I<superscript>2</superscript>C (or without fancy typography, "I2C")
|
|
||||||
is an acronym for the "Inter-IC" bus, a simple bus protocol which is
|
|
||||||
widely used where low data rate communications suffice.
|
|
||||||
Since it's also a licensed trademark, some vendors use another
|
|
||||||
name (such as "Two-Wire Interface", TWI) for the same bus.
|
|
||||||
I2C only needs two signals (SCL for clock, SDA for data), conserving
|
|
||||||
board real estate and minimizing signal quality issues.
|
|
||||||
Most I2C devices use seven bit addresses, and bus speeds of up
|
|
||||||
to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
|
|
||||||
found wide use.
|
|
||||||
I2C is a multi-master bus; open drain signaling is used to
|
|
||||||
arbitrate between masters, as well as to handshake and to
|
|
||||||
synchronize clocks from slower clients.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The Linux I2C programming interfaces support only the master
|
|
||||||
side of bus interactions, not the slave side.
|
|
||||||
The programming interface is structured around two kinds of driver,
|
|
||||||
and two kinds of device.
|
|
||||||
An I2C "Adapter Driver" abstracts the controller hardware; it binds
|
|
||||||
to a physical device (perhaps a PCI device or platform_device) and
|
|
||||||
exposes a <structname>struct i2c_adapter</structname> representing
|
|
||||||
each I2C bus segment it manages.
|
|
||||||
On each I2C bus segment will be I2C devices represented by a
|
|
||||||
<structname>struct i2c_client</structname>. Those devices will
|
|
||||||
be bound to a <structname>struct i2c_driver</structname>,
|
|
||||||
which should follow the standard Linux driver model.
|
|
||||||
(At this writing, a legacy model is more widely used.)
|
|
||||||
There are functions to perform various I2C protocol operations; at
|
|
||||||
this writing all such functions are usable only from task context.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
|
||||||
systems are also I2C conformant. The electrical constraints are
|
|
||||||
tighter for SMBus, and it standardizes particular protocol messages
|
|
||||||
and idioms. Controllers that support I2C can also support most
|
|
||||||
SMBus operations, but SMBus controllers don't support all the protocol
|
|
||||||
options that an I2C controller will.
|
|
||||||
There are functions to perform various SMBus protocol operations,
|
|
||||||
either using I2C primitives or by issuing SMBus commands to
|
|
||||||
i2c_adapter devices which don't support those I2C operations.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
!Iinclude/linux/i2c.h
|
|
||||||
!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
|
|
||||||
!Edrivers/i2c/i2c-core.c
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="hsi">
|
|
||||||
<title>High Speed Synchronous Serial Interface (HSI)</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
High Speed Synchronous Serial Interface (HSI) is a
|
|
||||||
serial interface mainly used for connecting application
|
|
||||||
engines (APE) with cellular modem engines (CMT) in cellular
|
|
||||||
handsets.
|
|
||||||
|
|
||||||
HSI provides multiplexing for up to 16 logical channels,
|
|
||||||
low-latency and full duplex communication.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
!Iinclude/linux/hsi/hsi.h
|
|
||||||
!Edrivers/hsi/hsi_core.c
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="pwm">
|
|
||||||
<title>Pulse-Width Modulation (PWM)</title>
|
|
||||||
<para>
|
|
||||||
Pulse-width modulation is a modulation technique primarily used to
|
|
||||||
control power supplied to electrical devices.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The PWM framework provides an abstraction for providers and consumers
|
|
||||||
of PWM signals. A controller that provides one or more PWM signals is
|
|
||||||
registered as <structname>struct pwm_chip</structname>. Providers are
|
|
||||||
expected to embed this structure in a driver-specific structure. This
|
|
||||||
structure contains fields that describe a particular chip.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
A chip exposes one or more PWM signal sources, each of which exposed
|
|
||||||
as a <structname>struct pwm_device</structname>. Operations can be
|
|
||||||
performed on PWM devices to control the period, duty cycle, polarity
|
|
||||||
and active state of the signal.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Note that PWM devices are exclusive resources: they can always only be
|
|
||||||
used by one consumer at a time.
|
|
||||||
</para>
|
|
||||||
!Iinclude/linux/pwm.h
|
|
||||||
!Edrivers/pwm/core.c
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
</book>
|
|
@@ -5,6 +5,9 @@
|
|||||||
# You can set these variables from the command line.
|
# You can set these variables from the command line.
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXBUILD = sphinx-build
|
||||||
SPHINXOPTS =
|
SPHINXOPTS =
|
||||||
|
SPHINXDIRS = .
|
||||||
|
_SPHINXDIRS = $(patsubst $(srctree)/Documentation/%/conf.py,%,$(wildcard $(srctree)/Documentation/*/conf.py))
|
||||||
|
SPHINX_CONF = conf.py
|
||||||
PAPER =
|
PAPER =
|
||||||
BUILDDIR = $(obj)/output
|
BUILDDIR = $(obj)/output
|
||||||
|
|
||||||
@@ -25,38 +28,62 @@ else ifneq ($(DOCBOOKS),)
|
|||||||
|
|
||||||
else # HAVE_SPHINX
|
else # HAVE_SPHINX
|
||||||
|
|
||||||
# User-friendly check for rst2pdf
|
# User-friendly check for pdflatex
|
||||||
HAVE_RST2PDF := $(shell if python -c "import rst2pdf" >/dev/null 2>&1; then echo 1; else echo 0; fi)
|
HAVE_PDFLATEX := $(shell if which xelatex >/dev/null 2>&1; then echo 1; else echo 0; fi)
|
||||||
|
|
||||||
# Internal variables.
|
# Internal variables.
|
||||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
KERNELDOC = $(srctree)/scripts/kernel-doc
|
KERNELDOC = $(srctree)/scripts/kernel-doc
|
||||||
KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC)
|
KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC)
|
||||||
ALLSPHINXOPTS = -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) -d $(BUILDDIR)/.doctrees $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) -c $(srctree)/$(src) $(SPHINXOPTS) $(srctree)/$(src)
|
ALLSPHINXOPTS = $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS)
|
||||||
# the i18n builder cannot share the environment and doctrees with the others
|
# the i18n builder cannot share the environment and doctrees with the others
|
||||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
quiet_cmd_sphinx = SPHINX $@
|
# commands; the 'cmd' from scripts/Kbuild.include is not *loopable*
|
||||||
cmd_sphinx = BUILDDIR=$(BUILDDIR) $(SPHINXBUILD) -b $2 $(ALLSPHINXOPTS) $(BUILDDIR)/$2
|
loop_cmd = $(echo-cmd) $(cmd_$(1))
|
||||||
|
|
||||||
|
# $2 sphinx builder e.g. "html"
|
||||||
|
# $3 name of the build subfolder / e.g. "media", used as:
|
||||||
|
# * dest folder relative to $(BUILDDIR) and
|
||||||
|
# * cache folder relative to $(BUILDDIR)/.doctrees
|
||||||
|
# $4 dest subfolder e.g. "man" for man pages at media/man
|
||||||
|
# $5 reST source folder relative to $(srctree)/$(src),
|
||||||
|
# e.g. "media" for the linux-tv book-set at ./Documentation/media
|
||||||
|
|
||||||
|
quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4);
|
||||||
|
cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media all;\
|
||||||
|
BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
|
||||||
|
$(SPHINXBUILD) \
|
||||||
|
-b $2 \
|
||||||
|
-c $(abspath $(srctree)/$(src)) \
|
||||||
|
-d $(abspath $(BUILDDIR)/.doctrees/$3) \
|
||||||
|
-D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) \
|
||||||
|
$(ALLSPHINXOPTS) \
|
||||||
|
$(abspath $(srctree)/$(src)/$5) \
|
||||||
|
$(abspath $(BUILDDIR)/$3/$4);
|
||||||
|
|
||||||
htmldocs:
|
htmldocs:
|
||||||
$(MAKE) BUILDDIR=$(BUILDDIR) -f $(srctree)/Documentation/media/Makefile $@
|
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var)))
|
||||||
$(call cmd,sphinx,html)
|
|
||||||
|
|
||||||
pdfdocs:
|
latexdocs:
|
||||||
ifeq ($(HAVE_RST2PDF),0)
|
ifeq ($(HAVE_PDFLATEX),0)
|
||||||
$(warning The Python 'rst2pdf' module was not found. Make sure you have the module installed to produce PDF output.)
|
$(warning The 'xelatex' command was not found. Make sure you have it installed and in PATH to produce PDF output.)
|
||||||
@echo " SKIP Sphinx $@ target."
|
@echo " SKIP Sphinx $@ target."
|
||||||
else # HAVE_RST2PDF
|
else # HAVE_PDFLATEX
|
||||||
$(call cmd,sphinx,pdf)
|
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,latex,$(var),latex,$(var)))
|
||||||
endif # HAVE_RST2PDF
|
endif # HAVE_PDFLATEX
|
||||||
|
|
||||||
|
pdfdocs: latexdocs
|
||||||
|
ifneq ($(HAVE_PDFLATEX),0)
|
||||||
|
$(foreach var,$(SPHINXDIRS), $(MAKE) PDFLATEX=xelatex LATEXOPTS="-interaction=nonstopmode" -C $(BUILDDIR)/$(var)/latex)
|
||||||
|
endif # HAVE_PDFLATEX
|
||||||
|
|
||||||
epubdocs:
|
epubdocs:
|
||||||
$(call cmd,sphinx,epub)
|
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,epub,$(var),epub,$(var)))
|
||||||
|
|
||||||
xmldocs:
|
xmldocs:
|
||||||
$(call cmd,sphinx,xml)
|
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,xml,$(var),xml,$(var)))
|
||||||
|
|
||||||
# no-ops for the Sphinx toolchain
|
# no-ops for the Sphinx toolchain
|
||||||
sgmldocs:
|
sgmldocs:
|
||||||
@@ -72,7 +99,14 @@ endif # HAVE_SPHINX
|
|||||||
dochelp:
|
dochelp:
|
||||||
@echo ' Linux kernel internal documentation in different formats (Sphinx):'
|
@echo ' Linux kernel internal documentation in different formats (Sphinx):'
|
||||||
@echo ' htmldocs - HTML'
|
@echo ' htmldocs - HTML'
|
||||||
|
@echo ' latexdocs - LaTeX'
|
||||||
@echo ' pdfdocs - PDF'
|
@echo ' pdfdocs - PDF'
|
||||||
@echo ' epubdocs - EPUB'
|
@echo ' epubdocs - EPUB'
|
||||||
@echo ' xmldocs - XML'
|
@echo ' xmldocs - XML'
|
||||||
@echo ' cleandocs - clean all generated files'
|
@echo ' cleandocs - clean all generated files'
|
||||||
|
@echo
|
||||||
|
@echo ' make SPHINXDIRS="s1 s2" [target] Generate only docs of folder s1, s2'
|
||||||
|
@echo ' valid values for SPHINXDIRS are: $(_SPHINXDIRS)'
|
||||||
|
@echo
|
||||||
|
@echo ' make SPHINX_CONF={conf-file} [target] use *additional* sphinx-build'
|
||||||
|
@echo ' configuration. This is e.g. useful to build with nit-picking config.'
|
||||||
|
@@ -73,4 +73,13 @@ SunXi family
|
|||||||
* Octa ARM Cortex-A7 based SoCs
|
* Octa ARM Cortex-A7 based SoCs
|
||||||
- Allwinner A83T
|
- Allwinner A83T
|
||||||
+ Datasheet
|
+ Datasheet
|
||||||
http://dl.linux-sunxi.org/A83T/A83T_datasheet_Revision_1.1.pdf
|
https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_Datasheet_v1.3_20150510.pdf
|
||||||
|
+ User Manual
|
||||||
|
https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_User_Manual_v1.5.1_20150513.pdf
|
||||||
|
|
||||||
|
* Quad ARM Cortex-A53 based SoCs
|
||||||
|
- Allwinner A64
|
||||||
|
+ Datasheet
|
||||||
|
http://dl.linux-sunxi.org/A64/A64_Datasheet_V1.1.pdf
|
||||||
|
+ User Manual
|
||||||
|
http://dl.linux-sunxi.org/A64/Allwinner%20A64%20User%20Manual%20v1.0.pdf
|
||||||
|
@@ -31,24 +31,25 @@ serve as a convenient shorthand for the implementation of the
|
|||||||
hardware-specific bits for the hypothetical "foo" hardware.
|
hardware-specific bits for the hypothetical "foo" hardware.
|
||||||
|
|
||||||
Tying the two halves of this interface together is struct clk_hw, which
|
Tying the two halves of this interface together is struct clk_hw, which
|
||||||
is defined in struct clk_foo and pointed to within struct clk. This
|
is defined in struct clk_foo and pointed to within struct clk_core. This
|
||||||
allows for easy navigation between the two discrete halves of the common
|
allows for easy navigation between the two discrete halves of the common
|
||||||
clock interface.
|
clock interface.
|
||||||
|
|
||||||
Part 2 - common data structures and api
|
Part 2 - common data structures and api
|
||||||
|
|
||||||
Below is the common struct clk definition from
|
Below is the common struct clk_core definition from
|
||||||
include/linux/clk-private.h, modified for brevity:
|
drivers/clk/clk.c, modified for brevity:
|
||||||
|
|
||||||
struct clk {
|
struct clk_core {
|
||||||
const char *name;
|
const char *name;
|
||||||
const struct clk_ops *ops;
|
const struct clk_ops *ops;
|
||||||
struct clk_hw *hw;
|
struct clk_hw *hw;
|
||||||
char **parent_names;
|
struct module *owner;
|
||||||
struct clk **parents;
|
struct clk_core *parent;
|
||||||
struct clk *parent;
|
const char **parent_names;
|
||||||
struct hlist_head children;
|
struct clk_core **parents;
|
||||||
struct hlist_node child_node;
|
u8 num_parents;
|
||||||
|
u8 new_parent_index;
|
||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,16 +57,19 @@ The members above make up the core of the clk tree topology. The clk
|
|||||||
api itself defines several driver-facing functions which operate on
|
api itself defines several driver-facing functions which operate on
|
||||||
struct clk. That api is documented in include/linux/clk.h.
|
struct clk. That api is documented in include/linux/clk.h.
|
||||||
|
|
||||||
Platforms and devices utilizing the common struct clk use the struct
|
Platforms and devices utilizing the common struct clk_core use the struct
|
||||||
clk_ops pointer in struct clk to perform the hardware-specific parts of
|
clk_ops pointer in struct clk_core to perform the hardware-specific parts of
|
||||||
the operations defined in clk.h:
|
the operations defined in clk-provider.h:
|
||||||
|
|
||||||
struct clk_ops {
|
struct clk_ops {
|
||||||
int (*prepare)(struct clk_hw *hw);
|
int (*prepare)(struct clk_hw *hw);
|
||||||
void (*unprepare)(struct clk_hw *hw);
|
void (*unprepare)(struct clk_hw *hw);
|
||||||
|
int (*is_prepared)(struct clk_hw *hw);
|
||||||
|
void (*unprepare_unused)(struct clk_hw *hw);
|
||||||
int (*enable)(struct clk_hw *hw);
|
int (*enable)(struct clk_hw *hw);
|
||||||
void (*disable)(struct clk_hw *hw);
|
void (*disable)(struct clk_hw *hw);
|
||||||
int (*is_enabled)(struct clk_hw *hw);
|
int (*is_enabled)(struct clk_hw *hw);
|
||||||
|
void (*disable_unused)(struct clk_hw *hw);
|
||||||
unsigned long (*recalc_rate)(struct clk_hw *hw,
|
unsigned long (*recalc_rate)(struct clk_hw *hw,
|
||||||
unsigned long parent_rate);
|
unsigned long parent_rate);
|
||||||
long (*round_rate)(struct clk_hw *hw,
|
long (*round_rate)(struct clk_hw *hw,
|
||||||
@@ -84,6 +88,8 @@ the operations defined in clk.h:
|
|||||||
u8 index);
|
u8 index);
|
||||||
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
|
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
|
||||||
unsigned long parent_accuracy);
|
unsigned long parent_accuracy);
|
||||||
|
int (*get_phase)(struct clk_hw *hw);
|
||||||
|
int (*set_phase)(struct clk_hw *hw, int degrees);
|
||||||
void (*init)(struct clk_hw *hw);
|
void (*init)(struct clk_hw *hw);
|
||||||
int (*debug_init)(struct clk_hw *hw,
|
int (*debug_init)(struct clk_hw *hw,
|
||||||
struct dentry *dentry);
|
struct dentry *dentry);
|
||||||
@@ -91,7 +97,7 @@ the operations defined in clk.h:
|
|||||||
|
|
||||||
Part 3 - hardware clk implementations
|
Part 3 - hardware clk implementations
|
||||||
|
|
||||||
The strength of the common struct clk comes from its .ops and .hw pointers
|
The strength of the common struct clk_core comes from its .ops and .hw pointers
|
||||||
which abstract the details of struct clk from the hardware-specific bits, and
|
which abstract the details of struct clk from the hardware-specific bits, and
|
||||||
vice versa. To illustrate consider the simple gateable clk implementation in
|
vice versa. To illustrate consider the simple gateable clk implementation in
|
||||||
drivers/clk/clk-gate.c:
|
drivers/clk/clk-gate.c:
|
||||||
@@ -107,7 +113,7 @@ struct clk_gate contains struct clk_hw hw as well as hardware-specific
|
|||||||
knowledge about which register and bit controls this clk's gating.
|
knowledge about which register and bit controls this clk's gating.
|
||||||
Nothing about clock topology or accounting, such as enable_count or
|
Nothing about clock topology or accounting, such as enable_count or
|
||||||
notifier_count, is needed here. That is all handled by the common
|
notifier_count, is needed here. That is all handled by the common
|
||||||
framework code and struct clk.
|
framework code and struct clk_core.
|
||||||
|
|
||||||
Let's walk through enabling this clk from driver code:
|
Let's walk through enabling this clk from driver code:
|
||||||
|
|
||||||
@@ -139,22 +145,18 @@ static void clk_gate_set_bit(struct clk_gate *gate)
|
|||||||
|
|
||||||
Note that to_clk_gate is defined as:
|
Note that to_clk_gate is defined as:
|
||||||
|
|
||||||
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk)
|
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
|
||||||
|
|
||||||
This pattern of abstraction is used for every clock hardware
|
This pattern of abstraction is used for every clock hardware
|
||||||
representation.
|
representation.
|
||||||
|
|
||||||
Part 4 - supporting your own clk hardware
|
Part 4 - supporting your own clk hardware
|
||||||
|
|
||||||
When implementing support for a new type of clock it only necessary to
|
When implementing support for a new type of clock it is only necessary to
|
||||||
include the following header:
|
include the following header:
|
||||||
|
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
|
|
||||||
include/linux/clk.h is included within that header and clk-private.h
|
|
||||||
must never be included from the code which implements the operations for
|
|
||||||
a clock. More on that below in Part 5.
|
|
||||||
|
|
||||||
To construct a clk hardware structure for your platform you must define
|
To construct a clk hardware structure for your platform you must define
|
||||||
the following:
|
the following:
|
||||||
|
|
||||||
|
@@ -14,11 +14,17 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import sphinx
|
||||||
|
|
||||||
|
# Get Sphinx version
|
||||||
|
major, minor, patch = map(int, sphinx.__version__.split("."))
|
||||||
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
sys.path.insert(0, os.path.abspath('sphinx'))
|
sys.path.insert(0, os.path.abspath('sphinx'))
|
||||||
|
from load_config import loadConfig
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
@@ -28,14 +34,13 @@ sys.path.insert(0, os.path.abspath('sphinx'))
|
|||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = ['kernel-doc', 'rstFlatTable', 'kernel_include']
|
extensions = ['kernel-doc', 'rstFlatTable', 'kernel_include', 'cdomain']
|
||||||
|
|
||||||
# Gracefully handle missing rst2pdf.
|
# The name of the math extension changed on Sphinx 1.4
|
||||||
try:
|
if minor > 3:
|
||||||
import rst2pdf
|
extensions.append("sphinx.ext.imgmath")
|
||||||
extensions += ['rst2pdf.pdfbuilder']
|
else:
|
||||||
except ImportError:
|
extensions.append("sphinx.ext.pngmath")
|
||||||
pass
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
@@ -252,23 +257,90 @@ htmlhelp_basename = 'TheLinuxKerneldoc'
|
|||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
'papersize': 'a4paper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#'pointsize': '10pt',
|
'pointsize': '8pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
#'preamble': '',
|
|
||||||
|
|
||||||
# Latex figure (float) alignment
|
# Latex figure (float) alignment
|
||||||
#'figure_align': 'htbp',
|
#'figure_align': 'htbp',
|
||||||
|
|
||||||
|
# Don't mangle with UTF-8 chars
|
||||||
|
'inputenc': '',
|
||||||
|
'utf8extra': '',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
'preamble': '''
|
||||||
|
% Adjust margins
|
||||||
|
\\usepackage[margin=0.5in, top=1in, bottom=1in]{geometry}
|
||||||
|
|
||||||
|
% Allow generate some pages in landscape
|
||||||
|
\\usepackage{lscape}
|
||||||
|
|
||||||
|
% Put notes in color and let them be inside a table
|
||||||
|
\\definecolor{NoteColor}{RGB}{204,255,255}
|
||||||
|
\\definecolor{WarningColor}{RGB}{255,204,204}
|
||||||
|
\\definecolor{AttentionColor}{RGB}{255,255,204}
|
||||||
|
\\definecolor{OtherColor}{RGB}{204,204,204}
|
||||||
|
\\newlength{\\mynoticelength}
|
||||||
|
\\makeatletter\\newenvironment{coloredbox}[1]{%
|
||||||
|
\\setlength{\\fboxrule}{1pt}
|
||||||
|
\\setlength{\\fboxsep}{7pt}
|
||||||
|
\\setlength{\\mynoticelength}{\\linewidth}
|
||||||
|
\\addtolength{\\mynoticelength}{-2\\fboxsep}
|
||||||
|
\\addtolength{\\mynoticelength}{-2\\fboxrule}
|
||||||
|
\\begin{lrbox}{\\@tempboxa}\\begin{minipage}{\\mynoticelength}}{\\end{minipage}\\end{lrbox}%
|
||||||
|
\\ifthenelse%
|
||||||
|
{\\equal{\\py@noticetype}{note}}%
|
||||||
|
{\\colorbox{NoteColor}{\\usebox{\\@tempboxa}}}%
|
||||||
|
{%
|
||||||
|
\\ifthenelse%
|
||||||
|
{\\equal{\\py@noticetype}{warning}}%
|
||||||
|
{\\colorbox{WarningColor}{\\usebox{\\@tempboxa}}}%
|
||||||
|
{%
|
||||||
|
\\ifthenelse%
|
||||||
|
{\\equal{\\py@noticetype}{attention}}%
|
||||||
|
{\\colorbox{AttentionColor}{\\usebox{\\@tempboxa}}}%
|
||||||
|
{\\colorbox{OtherColor}{\\usebox{\\@tempboxa}}}%
|
||||||
|
}%
|
||||||
|
}%
|
||||||
|
}\\makeatother
|
||||||
|
|
||||||
|
\\makeatletter
|
||||||
|
\\renewenvironment{notice}[2]{%
|
||||||
|
\\def\\py@noticetype{#1}
|
||||||
|
\\begin{coloredbox}{#1}
|
||||||
|
\\bf\\it
|
||||||
|
\\par\\strong{#2}
|
||||||
|
\\csname py@noticestart@#1\\endcsname
|
||||||
|
}
|
||||||
|
{
|
||||||
|
\\csname py@noticeend@\\py@noticetype\\endcsname
|
||||||
|
\\end{coloredbox}
|
||||||
|
}
|
||||||
|
\\makeatother
|
||||||
|
|
||||||
|
% Use some font with UTF-8 support with XeLaTeX
|
||||||
|
\\usepackage{fontspec}
|
||||||
|
\\setsansfont{DejaVu Serif}
|
||||||
|
\\setromanfont{DejaVu Sans}
|
||||||
|
\\setmonofont{DejaVu Sans Mono}
|
||||||
|
|
||||||
|
% To allow adjusting table sizes
|
||||||
|
\\usepackage{adjustbox}
|
||||||
|
|
||||||
|
'''
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
(master_doc, 'TheLinuxKernel.tex', 'The Linux Kernel Documentation',
|
('kernel-documentation', 'kernel-documentation.tex', 'The Linux Kernel Documentation',
|
||||||
|
'The kernel development community', 'manual'),
|
||||||
|
('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide',
|
||||||
|
'The kernel development community', 'manual'),
|
||||||
|
('media/index', 'media.tex', 'Linux Media Subsystem Documentation',
|
||||||
'The kernel development community', 'manual'),
|
'The kernel development community', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -419,3 +491,9 @@ pdf_documents = [
|
|||||||
# line arguments.
|
# line arguments.
|
||||||
kerneldoc_bin = '../scripts/kernel-doc'
|
kerneldoc_bin = '../scripts/kernel-doc'
|
||||||
kerneldoc_srctree = '..'
|
kerneldoc_srctree = '..'
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Since loadConfig overwrites settings from the global namespace, it has to be
|
||||||
|
# the last statement in the conf.py file
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
loadConfig(globals())
|
||||||
|
@@ -1,10 +1,18 @@
|
|||||||
Copyright 2010 Nicolas Palix <npalix@diku.dk>
|
.. Copyright 2010 Nicolas Palix <npalix@diku.dk>
|
||||||
Copyright 2010 Julia Lawall <julia@diku.dk>
|
.. Copyright 2010 Julia Lawall <julia@diku.dk>
|
||||||
Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
|
.. Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
|
||||||
|
|
||||||
|
.. highlight:: none
|
||||||
|
|
||||||
Getting Coccinelle
|
Coccinelle
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
==========
|
||||||
|
|
||||||
|
Coccinelle is a tool for pattern matching and text transformation that has
|
||||||
|
many uses in kernel development, including the application of complex,
|
||||||
|
tree-wide patches and detection of problematic programming patterns.
|
||||||
|
|
||||||
|
Getting Coccinelle
|
||||||
|
-------------------
|
||||||
|
|
||||||
The semantic patches included in the kernel use features and options
|
The semantic patches included in the kernel use features and options
|
||||||
which are provided by Coccinelle version 1.0.0-rc11 and above.
|
which are provided by Coccinelle version 1.0.0-rc11 and above.
|
||||||
@@ -22,24 +30,23 @@ of many distributions, e.g. :
|
|||||||
- NetBSD
|
- NetBSD
|
||||||
- FreeBSD
|
- FreeBSD
|
||||||
|
|
||||||
|
|
||||||
You can get the latest version released from the Coccinelle homepage at
|
You can get the latest version released from the Coccinelle homepage at
|
||||||
http://coccinelle.lip6.fr/
|
http://coccinelle.lip6.fr/
|
||||||
|
|
||||||
Information and tips about Coccinelle are also provided on the wiki
|
Information and tips about Coccinelle are also provided on the wiki
|
||||||
pages at http://cocci.ekstranet.diku.dk/wiki/doku.php
|
pages at http://cocci.ekstranet.diku.dk/wiki/doku.php
|
||||||
|
|
||||||
Once you have it, run the following command:
|
Once you have it, run the following command::
|
||||||
|
|
||||||
./configure
|
./configure
|
||||||
make
|
make
|
||||||
|
|
||||||
as a regular user, and install it with
|
as a regular user, and install it with::
|
||||||
|
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
Supplemental documentation
|
Supplemental documentation
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---------------------------
|
||||||
|
|
||||||
For supplemental documentation refer to the wiki:
|
For supplemental documentation refer to the wiki:
|
||||||
|
|
||||||
@@ -47,49 +54,52 @@ https://bottest.wiki.kernel.org/coccicheck
|
|||||||
|
|
||||||
The wiki documentation always refers to the linux-next version of the script.
|
The wiki documentation always refers to the linux-next version of the script.
|
||||||
|
|
||||||
Using Coccinelle on the Linux kernel
|
Using Coccinelle on the Linux kernel
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
------------------------------------
|
||||||
|
|
||||||
A Coccinelle-specific target is defined in the top level
|
A Coccinelle-specific target is defined in the top level
|
||||||
Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
|
Makefile. This target is named ``coccicheck`` and calls the ``coccicheck``
|
||||||
front-end in the 'scripts' directory.
|
front-end in the ``scripts`` directory.
|
||||||
|
|
||||||
Four basic modes are defined: patch, report, context, and org. The mode to
|
Four basic modes are defined: ``patch``, ``report``, ``context``, and
|
||||||
use is specified by setting the MODE variable with 'MODE=<mode>'.
|
``org``. The mode to use is specified by setting the MODE variable with
|
||||||
|
``MODE=<mode>``.
|
||||||
|
|
||||||
'patch' proposes a fix, when possible.
|
- ``patch`` proposes a fix, when possible.
|
||||||
|
|
||||||
'report' generates a list in the following format:
|
- ``report`` generates a list in the following format:
|
||||||
file:line:column-column: message
|
file:line:column-column: message
|
||||||
|
|
||||||
'context' highlights lines of interest and their context in a
|
- ``context`` highlights lines of interest and their context in a
|
||||||
diff-like style.Lines of interest are indicated with '-'.
|
diff-like style.Lines of interest are indicated with ``-``.
|
||||||
|
|
||||||
'org' generates a report in the Org mode format of Emacs.
|
- ``org`` generates a report in the Org mode format of Emacs.
|
||||||
|
|
||||||
Note that not all semantic patches implement all modes. For easy use
|
Note that not all semantic patches implement all modes. For easy use
|
||||||
of Coccinelle, the default mode is "report".
|
of Coccinelle, the default mode is "report".
|
||||||
|
|
||||||
Two other modes provide some common combinations of these modes.
|
Two other modes provide some common combinations of these modes.
|
||||||
|
|
||||||
'chain' tries the previous modes in the order above until one succeeds.
|
- ``chain`` tries the previous modes in the order above until one succeeds.
|
||||||
|
|
||||||
'rep+ctxt' runs successively the report mode and the context mode.
|
- ``rep+ctxt`` runs successively the report mode and the context mode.
|
||||||
It should be used with the C option (described later)
|
It should be used with the C option (described later)
|
||||||
which checks the code on a file basis.
|
which checks the code on a file basis.
|
||||||
|
|
||||||
Examples:
|
Examples
|
||||||
To make a report for every semantic patch, run the following command:
|
~~~~~~~~
|
||||||
|
|
||||||
|
To make a report for every semantic patch, run the following command::
|
||||||
|
|
||||||
make coccicheck MODE=report
|
make coccicheck MODE=report
|
||||||
|
|
||||||
To produce patches, run:
|
To produce patches, run::
|
||||||
|
|
||||||
make coccicheck MODE=patch
|
make coccicheck MODE=patch
|
||||||
|
|
||||||
|
|
||||||
The coccicheck target applies every semantic patch available in the
|
The coccicheck target applies every semantic patch available in the
|
||||||
sub-directories of 'scripts/coccinelle' to the entire Linux kernel.
|
sub-directories of ``scripts/coccinelle`` to the entire Linux kernel.
|
||||||
|
|
||||||
For each semantic patch, a commit message is proposed. It gives a
|
For each semantic patch, a commit message is proposed. It gives a
|
||||||
description of the problem being checked by the semantic patch, and
|
description of the problem being checked by the semantic patch, and
|
||||||
@@ -99,15 +109,15 @@ As any static code analyzer, Coccinelle produces false
|
|||||||
positives. Thus, reports must be carefully checked, and patches
|
positives. Thus, reports must be carefully checked, and patches
|
||||||
reviewed.
|
reviewed.
|
||||||
|
|
||||||
To enable verbose messages set the V= variable, for example:
|
To enable verbose messages set the V= variable, for example::
|
||||||
|
|
||||||
make coccicheck MODE=report V=1
|
make coccicheck MODE=report V=1
|
||||||
|
|
||||||
Coccinelle parallelization
|
Coccinelle parallelization
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---------------------------
|
||||||
|
|
||||||
By default, coccicheck tries to run as parallel as possible. To change
|
By default, coccicheck tries to run as parallel as possible. To change
|
||||||
the parallelism, set the J= variable. For example, to run across 4 CPUs:
|
the parallelism, set the J= variable. For example, to run across 4 CPUs::
|
||||||
|
|
||||||
make coccicheck MODE=report J=4
|
make coccicheck MODE=report J=4
|
||||||
|
|
||||||
@@ -115,44 +125,47 @@ As of Coccinelle 1.0.2 Coccinelle uses Ocaml parmap for parallelization,
|
|||||||
if support for this is detected you will benefit from parmap parallelization.
|
if support for this is detected you will benefit from parmap parallelization.
|
||||||
|
|
||||||
When parmap is enabled coccicheck will enable dynamic load balancing by using
|
When parmap is enabled coccicheck will enable dynamic load balancing by using
|
||||||
'--chunksize 1' argument, this ensures we keep feeding threads with work
|
``--chunksize 1`` argument, this ensures we keep feeding threads with work
|
||||||
one by one, so that we avoid the situation where most work gets done by only
|
one by one, so that we avoid the situation where most work gets done by only
|
||||||
a few threads. With dynamic load balancing, if a thread finishes early we keep
|
a few threads. With dynamic load balancing, if a thread finishes early we keep
|
||||||
feeding it more work.
|
feeding it more work.
|
||||||
|
|
||||||
When parmap is enabled, if an error occurs in Coccinelle, this error
|
When parmap is enabled, if an error occurs in Coccinelle, this error
|
||||||
value is propagated back, the return value of the 'make coccicheck'
|
value is propagated back, the return value of the ``make coccicheck``
|
||||||
captures this return value.
|
captures this return value.
|
||||||
|
|
||||||
Using Coccinelle with a single semantic patch
|
Using Coccinelle with a single semantic patch
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---------------------------------------------
|
||||||
|
|
||||||
The optional make variable COCCI can be used to check a single
|
The optional make variable COCCI can be used to check a single
|
||||||
semantic patch. In that case, the variable must be initialized with
|
semantic patch. In that case, the variable must be initialized with
|
||||||
the name of the semantic patch to apply.
|
the name of the semantic patch to apply.
|
||||||
|
|
||||||
For instance:
|
For instance::
|
||||||
|
|
||||||
make coccicheck COCCI=<my_SP.cocci> MODE=patch
|
make coccicheck COCCI=<my_SP.cocci> MODE=patch
|
||||||
or
|
|
||||||
|
or::
|
||||||
|
|
||||||
make coccicheck COCCI=<my_SP.cocci> MODE=report
|
make coccicheck COCCI=<my_SP.cocci> MODE=report
|
||||||
|
|
||||||
|
|
||||||
Controlling Which Files are Processed by Coccinelle
|
Controlling Which Files are Processed by Coccinelle
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---------------------------------------------------
|
||||||
|
|
||||||
By default the entire kernel source tree is checked.
|
By default the entire kernel source tree is checked.
|
||||||
|
|
||||||
To apply Coccinelle to a specific directory, M= can be used.
|
To apply Coccinelle to a specific directory, ``M=`` can be used.
|
||||||
For example, to check drivers/net/wireless/ one may write:
|
For example, to check drivers/net/wireless/ one may write::
|
||||||
|
|
||||||
make coccicheck M=drivers/net/wireless/
|
make coccicheck M=drivers/net/wireless/
|
||||||
|
|
||||||
To apply Coccinelle on a file basis, instead of a directory basis, the
|
To apply Coccinelle on a file basis, instead of a directory basis, the
|
||||||
following command may be used:
|
following command may be used::
|
||||||
|
|
||||||
make C=1 CHECK="scripts/coccicheck"
|
make C=1 CHECK="scripts/coccicheck"
|
||||||
|
|
||||||
To check only newly edited code, use the value 2 for the C flag, i.e.
|
To check only newly edited code, use the value 2 for the C flag, i.e.::
|
||||||
|
|
||||||
make C=2 CHECK="scripts/coccicheck"
|
make C=2 CHECK="scripts/coccicheck"
|
||||||
|
|
||||||
@@ -166,8 +179,8 @@ semantic patch as shown in the previous section.
|
|||||||
The "report" mode is the default. You can select another one with the
|
The "report" mode is the default. You can select another one with the
|
||||||
MODE variable explained above.
|
MODE variable explained above.
|
||||||
|
|
||||||
Debugging Coccinelle SmPL patches
|
Debugging Coccinelle SmPL patches
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---------------------------------
|
||||||
|
|
||||||
Using coccicheck is best as it provides in the spatch command line
|
Using coccicheck is best as it provides in the spatch command line
|
||||||
include options matching the options used when we compile the kernel.
|
include options matching the options used when we compile the kernel.
|
||||||
@@ -177,8 +190,8 @@ manually run Coccinelle with debug options added.
|
|||||||
Alternatively you can debug running Coccinelle against SmPL patches
|
Alternatively you can debug running Coccinelle against SmPL patches
|
||||||
by asking for stderr to be redirected to stderr, by default stderr
|
by asking for stderr to be redirected to stderr, by default stderr
|
||||||
is redirected to /dev/null, if you'd like to capture stderr you
|
is redirected to /dev/null, if you'd like to capture stderr you
|
||||||
can specify the DEBUG_FILE="file.txt" option to coccicheck. For
|
can specify the ``DEBUG_FILE="file.txt"`` option to coccicheck. For
|
||||||
instance:
|
instance::
|
||||||
|
|
||||||
rm -f cocci.err
|
rm -f cocci.err
|
||||||
make coccicheck COCCI=scripts/coccinelle/free/kfree.cocci MODE=report DEBUG_FILE=cocci.err
|
make coccicheck COCCI=scripts/coccinelle/free/kfree.cocci MODE=report DEBUG_FILE=cocci.err
|
||||||
@@ -186,7 +199,7 @@ instance:
|
|||||||
|
|
||||||
You can use SPFLAGS to add debugging flags, for instance you may want to
|
You can use SPFLAGS to add debugging flags, for instance you may want to
|
||||||
add both --profile --show-trying to SPFLAGS when debugging. For instance
|
add both --profile --show-trying to SPFLAGS when debugging. For instance
|
||||||
you may want to use:
|
you may want to use::
|
||||||
|
|
||||||
rm -f err.log
|
rm -f err.log
|
||||||
export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
|
export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
|
||||||
@@ -198,24 +211,24 @@ work.
|
|||||||
|
|
||||||
DEBUG_FILE support is only supported when using coccinelle >= 1.2.
|
DEBUG_FILE support is only supported when using coccinelle >= 1.2.
|
||||||
|
|
||||||
.cocciconfig support
|
.cocciconfig support
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
--------------------
|
||||||
|
|
||||||
Coccinelle supports reading .cocciconfig for default Coccinelle options that
|
Coccinelle supports reading .cocciconfig for default Coccinelle options that
|
||||||
should be used every time spatch is spawned, the order of precedence for
|
should be used every time spatch is spawned, the order of precedence for
|
||||||
variables for .cocciconfig is as follows:
|
variables for .cocciconfig is as follows:
|
||||||
|
|
||||||
o Your current user's home directory is processed first
|
- Your current user's home directory is processed first
|
||||||
o Your directory from which spatch is called is processed next
|
- Your directory from which spatch is called is processed next
|
||||||
o The directory provided with the --dir option is processed last, if used
|
- The directory provided with the --dir option is processed last, if used
|
||||||
|
|
||||||
Since coccicheck runs through make, it naturally runs from the kernel
|
Since coccicheck runs through make, it naturally runs from the kernel
|
||||||
proper dir, as such the second rule above would be implied for picking up a
|
proper dir, as such the second rule above would be implied for picking up a
|
||||||
.cocciconfig when using 'make coccicheck'.
|
.cocciconfig when using ``make coccicheck``.
|
||||||
|
|
||||||
'make coccicheck' also supports using M= targets.If you do not supply
|
``make coccicheck`` also supports using M= targets.If you do not supply
|
||||||
any M= target, it is assumed you want to target the entire kernel.
|
any M= target, it is assumed you want to target the entire kernel.
|
||||||
The kernel coccicheck script has:
|
The kernel coccicheck script has::
|
||||||
|
|
||||||
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
||||||
OPTIONS="--dir $srctree $COCCIINCLUDE"
|
OPTIONS="--dir $srctree $COCCIINCLUDE"
|
||||||
@@ -235,12 +248,12 @@ override any of the kernel's .coccicheck's settings using SPFLAGS.
|
|||||||
|
|
||||||
We help Coccinelle when used against Linux with a set of sensible defaults
|
We help Coccinelle when used against Linux with a set of sensible defaults
|
||||||
options for Linux with our own Linux .cocciconfig. This hints to coccinelle
|
options for Linux with our own Linux .cocciconfig. This hints to coccinelle
|
||||||
git can be used for 'git grep' queries over coccigrep. A timeout of 200
|
git can be used for ``git grep`` queries over coccigrep. A timeout of 200
|
||||||
seconds should suffice for now.
|
seconds should suffice for now.
|
||||||
|
|
||||||
The options picked up by coccinelle when reading a .cocciconfig do not appear
|
The options picked up by coccinelle when reading a .cocciconfig do not appear
|
||||||
as arguments to spatch processes running on your system, to confirm what
|
as arguments to spatch processes running on your system, to confirm what
|
||||||
options will be used by Coccinelle run:
|
options will be used by Coccinelle run::
|
||||||
|
|
||||||
spatch --print-options-only
|
spatch --print-options-only
|
||||||
|
|
||||||
@@ -252,219 +265,227 @@ carries its own .cocciconfig, you will need to use SPFLAGS to use idutils if
|
|||||||
desired. See below section "Additional flags" for more details on how to use
|
desired. See below section "Additional flags" for more details on how to use
|
||||||
idutils.
|
idutils.
|
||||||
|
|
||||||
Additional flags
|
Additional flags
|
||||||
~~~~~~~~~~~~~~~~~~
|
----------------
|
||||||
|
|
||||||
Additional flags can be passed to spatch through the SPFLAGS
|
Additional flags can be passed to spatch through the SPFLAGS
|
||||||
variable. This works as Coccinelle respects the last flags
|
variable. This works as Coccinelle respects the last flags
|
||||||
given to it when options are in conflict.
|
given to it when options are in conflict. ::
|
||||||
|
|
||||||
make SPFLAGS=--use-glimpse coccicheck
|
make SPFLAGS=--use-glimpse coccicheck
|
||||||
|
|
||||||
Coccinelle supports idutils as well but requires coccinelle >= 1.0.6.
|
Coccinelle supports idutils as well but requires coccinelle >= 1.0.6.
|
||||||
When no ID file is specified coccinelle assumes your ID database file
|
When no ID file is specified coccinelle assumes your ID database file
|
||||||
is in the file .id-utils.index on the top level of the kernel, coccinelle
|
is in the file .id-utils.index on the top level of the kernel, coccinelle
|
||||||
carries a script scripts/idutils_index.sh which creates the database with
|
carries a script scripts/idutils_index.sh which creates the database with::
|
||||||
|
|
||||||
mkid -i C --output .id-utils.index
|
mkid -i C --output .id-utils.index
|
||||||
|
|
||||||
If you have another database filename you can also just symlink with this
|
If you have another database filename you can also just symlink with this
|
||||||
name.
|
name. ::
|
||||||
|
|
||||||
make SPFLAGS=--use-idutils coccicheck
|
make SPFLAGS=--use-idutils coccicheck
|
||||||
|
|
||||||
Alternatively you can specify the database filename explicitly, for
|
Alternatively you can specify the database filename explicitly, for
|
||||||
instance:
|
instance::
|
||||||
|
|
||||||
make SPFLAGS="--use-idutils /full-path/to/ID" coccicheck
|
make SPFLAGS="--use-idutils /full-path/to/ID" coccicheck
|
||||||
|
|
||||||
See spatch --help to learn more about spatch options.
|
See ``spatch --help`` to learn more about spatch options.
|
||||||
|
|
||||||
Note that the '--use-glimpse' and '--use-idutils' options
|
Note that the ``--use-glimpse`` and ``--use-idutils`` options
|
||||||
require external tools for indexing the code. None of them is
|
require external tools for indexing the code. None of them is
|
||||||
thus active by default. However, by indexing the code with
|
thus active by default. However, by indexing the code with
|
||||||
one of these tools, and according to the cocci file used,
|
one of these tools, and according to the cocci file used,
|
||||||
spatch could proceed the entire code base more quickly.
|
spatch could proceed the entire code base more quickly.
|
||||||
|
|
||||||
SmPL patch specific options
|
SmPL patch specific options
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
---------------------------
|
||||||
|
|
||||||
SmPL patches can have their own requirements for options passed
|
SmPL patches can have their own requirements for options passed
|
||||||
to Coccinelle. SmPL patch specific options can be provided by
|
to Coccinelle. SmPL patch specific options can be provided by
|
||||||
providing them at the top of the SmPL patch, for instance:
|
providing them at the top of the SmPL patch, for instance::
|
||||||
|
|
||||||
// Options: --no-includes --include-headers
|
// Options: --no-includes --include-headers
|
||||||
|
|
||||||
SmPL patch Coccinelle requirements
|
SmPL patch Coccinelle requirements
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
----------------------------------
|
||||||
|
|
||||||
As Coccinelle features get added some more advanced SmPL patches
|
As Coccinelle features get added some more advanced SmPL patches
|
||||||
may require newer versions of Coccinelle. If an SmPL patch requires
|
may require newer versions of Coccinelle. If an SmPL patch requires
|
||||||
at least a version of Coccinelle, this can be specified as follows,
|
at least a version of Coccinelle, this can be specified as follows,
|
||||||
as an example if requiring at least Coccinelle >= 1.0.5:
|
as an example if requiring at least Coccinelle >= 1.0.5::
|
||||||
|
|
||||||
// Requires: 1.0.5
|
// Requires: 1.0.5
|
||||||
|
|
||||||
Proposing new semantic patches
|
Proposing new semantic patches
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
-------------------------------
|
||||||
|
|
||||||
New semantic patches can be proposed and submitted by kernel
|
New semantic patches can be proposed and submitted by kernel
|
||||||
developers. For sake of clarity, they should be organized in the
|
developers. For sake of clarity, they should be organized in the
|
||||||
sub-directories of 'scripts/coccinelle/'.
|
sub-directories of ``scripts/coccinelle/``.
|
||||||
|
|
||||||
|
|
||||||
Detailed description of the 'report' mode
|
Detailed description of the ``report`` mode
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
-------------------------------------------
|
||||||
|
|
||||||
|
``report`` generates a list in the following format::
|
||||||
|
|
||||||
'report' generates a list in the following format:
|
|
||||||
file:line:column-column: message
|
file:line:column-column: message
|
||||||
|
|
||||||
Example:
|
Example
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
Running
|
Running::
|
||||||
|
|
||||||
make coccicheck MODE=report COCCI=scripts/coccinelle/api/err_cast.cocci
|
make coccicheck MODE=report COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script::
|
||||||
|
|
||||||
<smpl>
|
<smpl>
|
||||||
@r depends on !context && !patch && (org || report)@
|
@r depends on !context && !patch && (org || report)@
|
||||||
expression x;
|
expression x;
|
||||||
position p;
|
position p;
|
||||||
@@
|
@@
|
||||||
|
|
||||||
ERR_PTR@p(PTR_ERR(x))
|
ERR_PTR@p(PTR_ERR(x))
|
||||||
|
|
||||||
@script:python depends on report@
|
@script:python depends on report@
|
||||||
p << r.p;
|
p << r.p;
|
||||||
x << r.x;
|
x << r.x;
|
||||||
@@
|
@@
|
||||||
|
|
||||||
msg="ERR_CAST can be used with %s" % (x)
|
msg="ERR_CAST can be used with %s" % (x)
|
||||||
coccilib.report.print_report(p[0], msg)
|
coccilib.report.print_report(p[0], msg)
|
||||||
</smpl>
|
</smpl>
|
||||||
|
|
||||||
This SmPL excerpt generates entries on the standard output, as
|
This SmPL excerpt generates entries on the standard output, as
|
||||||
illustrated below:
|
illustrated below::
|
||||||
|
|
||||||
/home/user/linux/crypto/ctr.c:188:9-16: ERR_CAST can be used with alg
|
/home/user/linux/crypto/ctr.c:188:9-16: ERR_CAST can be used with alg
|
||||||
/home/user/linux/crypto/authenc.c:619:9-16: ERR_CAST can be used with auth
|
/home/user/linux/crypto/authenc.c:619:9-16: ERR_CAST can be used with auth
|
||||||
/home/user/linux/crypto/xts.c:227:9-16: ERR_CAST can be used with alg
|
/home/user/linux/crypto/xts.c:227:9-16: ERR_CAST can be used with alg
|
||||||
|
|
||||||
|
|
||||||
Detailed description of the 'patch' mode
|
Detailed description of the ``patch`` mode
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
------------------------------------------
|
||||||
|
|
||||||
When the 'patch' mode is available, it proposes a fix for each problem
|
When the ``patch`` mode is available, it proposes a fix for each problem
|
||||||
identified.
|
identified.
|
||||||
|
|
||||||
Example:
|
Example
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Running::
|
||||||
|
|
||||||
Running
|
|
||||||
make coccicheck MODE=patch COCCI=scripts/coccinelle/api/err_cast.cocci
|
make coccicheck MODE=patch COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script::
|
||||||
|
|
||||||
<smpl>
|
<smpl>
|
||||||
@ depends on !context && patch && !org && !report @
|
@ depends on !context && patch && !org && !report @
|
||||||
expression x;
|
expression x;
|
||||||
@@
|
@@
|
||||||
|
|
||||||
- ERR_PTR(PTR_ERR(x))
|
- ERR_PTR(PTR_ERR(x))
|
||||||
+ ERR_CAST(x)
|
+ ERR_CAST(x)
|
||||||
</smpl>
|
</smpl>
|
||||||
|
|
||||||
This SmPL excerpt generates patch hunks on the standard output, as
|
This SmPL excerpt generates patch hunks on the standard output, as
|
||||||
illustrated below:
|
illustrated below::
|
||||||
|
|
||||||
diff -u -p a/crypto/ctr.c b/crypto/ctr.c
|
diff -u -p a/crypto/ctr.c b/crypto/ctr.c
|
||||||
--- a/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
--- a/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
||||||
+++ b/crypto/ctr.c 2010-06-03 23:44:49.000000000 +0200
|
+++ b/crypto/ctr.c 2010-06-03 23:44:49.000000000 +0200
|
||||||
@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ct
|
@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ct
|
||||||
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
|
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
|
||||||
CRYPTO_ALG_TYPE_MASK);
|
CRYPTO_ALG_TYPE_MASK);
|
||||||
if (IS_ERR(alg))
|
if (IS_ERR(alg))
|
||||||
- return ERR_PTR(PTR_ERR(alg));
|
- return ERR_PTR(PTR_ERR(alg));
|
||||||
+ return ERR_CAST(alg);
|
+ return ERR_CAST(alg);
|
||||||
|
|
||||||
/* Block size must be >= 4 bytes. */
|
/* Block size must be >= 4 bytes. */
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
Detailed description of the 'context' mode
|
Detailed description of the ``context`` mode
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
--------------------------------------------
|
||||||
|
|
||||||
'context' highlights lines of interest and their context
|
``context`` highlights lines of interest and their context
|
||||||
in a diff-like style.
|
in a diff-like style.
|
||||||
|
|
||||||
NOTE: The diff-like output generated is NOT an applicable patch. The
|
**NOTE**: The diff-like output generated is NOT an applicable patch. The
|
||||||
intent of the 'context' mode is to highlight the important lines
|
intent of the ``context`` mode is to highlight the important lines
|
||||||
(annotated with minus, '-') and gives some surrounding context
|
(annotated with minus, ``-``) and gives some surrounding context
|
||||||
lines around. This output can be used with the diff mode of
|
lines around. This output can be used with the diff mode of
|
||||||
Emacs to review the code.
|
Emacs to review the code.
|
||||||
|
|
||||||
Example:
|
Example
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Running::
|
||||||
|
|
||||||
Running
|
|
||||||
make coccicheck MODE=context COCCI=scripts/coccinelle/api/err_cast.cocci
|
make coccicheck MODE=context COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script::
|
||||||
|
|
||||||
<smpl>
|
<smpl>
|
||||||
@ depends on context && !patch && !org && !report@
|
@ depends on context && !patch && !org && !report@
|
||||||
expression x;
|
expression x;
|
||||||
@@
|
@@
|
||||||
|
|
||||||
* ERR_PTR(PTR_ERR(x))
|
* ERR_PTR(PTR_ERR(x))
|
||||||
</smpl>
|
</smpl>
|
||||||
|
|
||||||
This SmPL excerpt generates diff hunks on the standard output, as
|
This SmPL excerpt generates diff hunks on the standard output, as
|
||||||
illustrated below:
|
illustrated below::
|
||||||
|
|
||||||
diff -u -p /home/user/linux/crypto/ctr.c /tmp/nothing
|
diff -u -p /home/user/linux/crypto/ctr.c /tmp/nothing
|
||||||
--- /home/user/linux/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
--- /home/user/linux/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
||||||
+++ /tmp/nothing
|
+++ /tmp/nothing
|
||||||
@@ -185,7 +185,6 @@ static struct crypto_instance *crypto_ct
|
@@ -185,7 +185,6 @@ static struct crypto_instance *crypto_ct
|
||||||
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
|
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
|
||||||
CRYPTO_ALG_TYPE_MASK);
|
CRYPTO_ALG_TYPE_MASK);
|
||||||
if (IS_ERR(alg))
|
if (IS_ERR(alg))
|
||||||
- return ERR_PTR(PTR_ERR(alg));
|
- return ERR_PTR(PTR_ERR(alg));
|
||||||
|
|
||||||
/* Block size must be >= 4 bytes. */
|
/* Block size must be >= 4 bytes. */
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
Detailed description of the 'org' mode
|
Detailed description of the ``org`` mode
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
----------------------------------------
|
||||||
|
|
||||||
'org' generates a report in the Org mode format of Emacs.
|
``org`` generates a report in the Org mode format of Emacs.
|
||||||
|
|
||||||
Example:
|
Example
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Running::
|
||||||
|
|
||||||
Running
|
|
||||||
make coccicheck MODE=org COCCI=scripts/coccinelle/api/err_cast.cocci
|
make coccicheck MODE=org COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script::
|
||||||
|
|
||||||
<smpl>
|
<smpl>
|
||||||
@r depends on !context && !patch && (org || report)@
|
@r depends on !context && !patch && (org || report)@
|
||||||
expression x;
|
expression x;
|
||||||
position p;
|
position p;
|
||||||
@@
|
@@
|
||||||
|
|
||||||
ERR_PTR@p(PTR_ERR(x))
|
ERR_PTR@p(PTR_ERR(x))
|
||||||
|
|
||||||
@script:python depends on org@
|
@script:python depends on org@
|
||||||
p << r.p;
|
p << r.p;
|
||||||
x << r.x;
|
x << r.x;
|
||||||
@@
|
@@
|
||||||
|
|
||||||
msg="ERR_CAST can be used with %s" % (x)
|
msg="ERR_CAST can be used with %s" % (x)
|
||||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||||
coccilib.org.print_todo(p[0], msg_safe)
|
coccilib.org.print_todo(p[0], msg_safe)
|
||||||
</smpl>
|
</smpl>
|
||||||
|
|
||||||
This SmPL excerpt generates Org entries on the standard output, as
|
This SmPL excerpt generates Org entries on the standard output, as
|
||||||
illustrated below:
|
illustrated below::
|
||||||
|
|
||||||
* TODO [[view:/home/user/linux/crypto/ctr.c::face=ovl-face1::linb=188::colb=9::cole=16][ERR_CAST can be used with alg]]
|
* TODO [[view:/home/user/linux/crypto/ctr.c::face=ovl-face1::linb=188::colb=9::cole=16][ERR_CAST can be used with alg]]
|
||||||
* TODO [[view:/home/user/linux/crypto/authenc.c::face=ovl-face1::linb=619::colb=9::cole=16][ERR_CAST can be used with auth]]
|
* TODO [[view:/home/user/linux/crypto/authenc.c::face=ovl-face1::linb=619::colb=9::cole=16][ERR_CAST can be used with auth]]
|
||||||
* TODO [[view:/home/user/linux/crypto/xts.c::face=ovl-face1::linb=227::colb=9::cole=16][ERR_CAST can be used with alg]]
|
* TODO [[view:/home/user/linux/crypto/xts.c::face=ovl-face1::linb=227::colb=9::cole=16][ERR_CAST can be used with alg]]
|
256
Documentation/dev-tools/gcov.rst
Normal file
256
Documentation/dev-tools/gcov.rst
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
Using gcov with the Linux kernel
|
||||||
|
================================
|
||||||
|
|
||||||
|
gcov profiling kernel support enables the use of GCC's coverage testing
|
||||||
|
tool gcov_ with the Linux kernel. Coverage data of a running kernel
|
||||||
|
is exported in gcov-compatible format via the "gcov" debugfs directory.
|
||||||
|
To get coverage data for a specific file, change to the kernel build
|
||||||
|
directory and use gcov with the ``-o`` option as follows (requires root)::
|
||||||
|
|
||||||
|
# cd /tmp/linux-out
|
||||||
|
# gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
|
||||||
|
|
||||||
|
This will create source code files annotated with execution counts
|
||||||
|
in the current directory. In addition, graphical gcov front-ends such
|
||||||
|
as lcov_ can be used to automate the process of collecting data
|
||||||
|
for the entire kernel and provide coverage overviews in HTML format.
|
||||||
|
|
||||||
|
Possible uses:
|
||||||
|
|
||||||
|
* debugging (has this line been reached at all?)
|
||||||
|
* test improvement (how do I change my test to cover these lines?)
|
||||||
|
* minimizing kernel configurations (do I need this option if the
|
||||||
|
associated code is never run?)
|
||||||
|
|
||||||
|
.. _gcov: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
|
||||||
|
.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
|
||||||
|
|
||||||
|
|
||||||
|
Preparation
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Configure the kernel with::
|
||||||
|
|
||||||
|
CONFIG_DEBUG_FS=y
|
||||||
|
CONFIG_GCOV_KERNEL=y
|
||||||
|
|
||||||
|
select the gcc's gcov format, default is autodetect based on gcc version::
|
||||||
|
|
||||||
|
CONFIG_GCOV_FORMAT_AUTODETECT=y
|
||||||
|
|
||||||
|
and to get coverage data for the entire kernel::
|
||||||
|
|
||||||
|
CONFIG_GCOV_PROFILE_ALL=y
|
||||||
|
|
||||||
|
Note that kernels compiled with profiling flags will be significantly
|
||||||
|
larger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
|
||||||
|
on all architectures.
|
||||||
|
|
||||||
|
Profiling data will only become accessible once debugfs has been
|
||||||
|
mounted::
|
||||||
|
|
||||||
|
mount -t debugfs none /sys/kernel/debug
|
||||||
|
|
||||||
|
|
||||||
|
Customization
|
||||||
|
-------------
|
||||||
|
|
||||||
|
To enable profiling for specific files or directories, add a line
|
||||||
|
similar to the following to the respective kernel Makefile:
|
||||||
|
|
||||||
|
- For a single file (e.g. main.o)::
|
||||||
|
|
||||||
|
GCOV_PROFILE_main.o := y
|
||||||
|
|
||||||
|
- For all files in one directory::
|
||||||
|
|
||||||
|
GCOV_PROFILE := y
|
||||||
|
|
||||||
|
To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
|
||||||
|
is specified, use::
|
||||||
|
|
||||||
|
GCOV_PROFILE_main.o := n
|
||||||
|
|
||||||
|
and::
|
||||||
|
|
||||||
|
GCOV_PROFILE := n
|
||||||
|
|
||||||
|
Only files which are linked to the main kernel image or are compiled as
|
||||||
|
kernel modules are supported by this mechanism.
|
||||||
|
|
||||||
|
|
||||||
|
Files
|
||||||
|
-----
|
||||||
|
|
||||||
|
The gcov kernel support creates the following files in debugfs:
|
||||||
|
|
||||||
|
``/sys/kernel/debug/gcov``
|
||||||
|
Parent directory for all gcov-related files.
|
||||||
|
|
||||||
|
``/sys/kernel/debug/gcov/reset``
|
||||||
|
Global reset file: resets all coverage data to zero when
|
||||||
|
written to.
|
||||||
|
|
||||||
|
``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda``
|
||||||
|
The actual gcov data file as understood by the gcov
|
||||||
|
tool. Resets file coverage data to zero when written to.
|
||||||
|
|
||||||
|
``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno``
|
||||||
|
Symbolic link to a static data file required by the gcov
|
||||||
|
tool. This file is generated by gcc when compiling with
|
||||||
|
option ``-ftest-coverage``.
|
||||||
|
|
||||||
|
|
||||||
|
Modules
|
||||||
|
-------
|
||||||
|
|
||||||
|
Kernel modules may contain cleanup code which is only run during
|
||||||
|
module unload time. The gcov mechanism provides a means to collect
|
||||||
|
coverage data for such code by keeping a copy of the data associated
|
||||||
|
with the unloaded module. This data remains available through debugfs.
|
||||||
|
Once the module is loaded again, the associated coverage counters are
|
||||||
|
initialized with the data from its previous instantiation.
|
||||||
|
|
||||||
|
This behavior can be deactivated by specifying the gcov_persist kernel
|
||||||
|
parameter::
|
||||||
|
|
||||||
|
gcov_persist=0
|
||||||
|
|
||||||
|
At run-time, a user can also choose to discard data for an unloaded
|
||||||
|
module by writing to its data file or the global reset file.
|
||||||
|
|
||||||
|
|
||||||
|
Separated build and test machines
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
The gcov kernel profiling infrastructure is designed to work out-of-the
|
||||||
|
box for setups where kernels are built and run on the same machine. In
|
||||||
|
cases where the kernel runs on a separate machine, special preparations
|
||||||
|
must be made, depending on where the gcov tool is used:
|
||||||
|
|
||||||
|
a) gcov is run on the TEST machine
|
||||||
|
|
||||||
|
The gcov tool version on the test machine must be compatible with the
|
||||||
|
gcc version used for kernel build. Also the following files need to be
|
||||||
|
copied from build to test machine:
|
||||||
|
|
||||||
|
from the source tree:
|
||||||
|
- all C source files + headers
|
||||||
|
|
||||||
|
from the build tree:
|
||||||
|
- all C source files + headers
|
||||||
|
- all .gcda and .gcno files
|
||||||
|
- all links to directories
|
||||||
|
|
||||||
|
It is important to note that these files need to be placed into the
|
||||||
|
exact same file system location on the test machine as on the build
|
||||||
|
machine. If any of the path components is symbolic link, the actual
|
||||||
|
directory needs to be used instead (due to make's CURDIR handling).
|
||||||
|
|
||||||
|
b) gcov is run on the BUILD machine
|
||||||
|
|
||||||
|
The following files need to be copied after each test case from test
|
||||||
|
to build machine:
|
||||||
|
|
||||||
|
from the gcov directory in sysfs:
|
||||||
|
- all .gcda files
|
||||||
|
- all links to .gcno files
|
||||||
|
|
||||||
|
These files can be copied to any location on the build machine. gcov
|
||||||
|
must then be called with the -o option pointing to that directory.
|
||||||
|
|
||||||
|
Example directory setup on the build machine::
|
||||||
|
|
||||||
|
/tmp/linux: kernel source tree
|
||||||
|
/tmp/out: kernel build directory as specified by make O=
|
||||||
|
/tmp/coverage: location of the files copied from the test machine
|
||||||
|
|
||||||
|
[user@build] cd /tmp/out
|
||||||
|
[user@build] gcov -o /tmp/coverage/tmp/out/init main.c
|
||||||
|
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Problem
|
||||||
|
Compilation aborts during linker step.
|
||||||
|
|
||||||
|
Cause
|
||||||
|
Profiling flags are specified for source files which are not
|
||||||
|
linked to the main kernel or which are linked by a custom
|
||||||
|
linker procedure.
|
||||||
|
|
||||||
|
Solution
|
||||||
|
Exclude affected source files from profiling by specifying
|
||||||
|
``GCOV_PROFILE := n`` or ``GCOV_PROFILE_basename.o := n`` in the
|
||||||
|
corresponding Makefile.
|
||||||
|
|
||||||
|
Problem
|
||||||
|
Files copied from sysfs appear empty or incomplete.
|
||||||
|
|
||||||
|
Cause
|
||||||
|
Due to the way seq_file works, some tools such as cp or tar
|
||||||
|
may not correctly copy files from sysfs.
|
||||||
|
|
||||||
|
Solution
|
||||||
|
Use ``cat``' to read ``.gcda`` files and ``cp -d`` to copy links.
|
||||||
|
Alternatively use the mechanism shown in Appendix B.
|
||||||
|
|
||||||
|
|
||||||
|
Appendix A: gather_on_build.sh
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Sample script to gather coverage meta files on the build machine
|
||||||
|
(see 6a)::
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
KSRC=$1
|
||||||
|
KOBJ=$2
|
||||||
|
DEST=$3
|
||||||
|
|
||||||
|
if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
|
||||||
|
echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
||||||
|
KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
||||||
|
|
||||||
|
find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
|
||||||
|
-perm /u+r,g+r | tar cfz $DEST -P -T -
|
||||||
|
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
echo "$DEST successfully created, copy to test system and unpack with:"
|
||||||
|
echo " tar xfz $DEST -P"
|
||||||
|
else
|
||||||
|
echo "Could not create file $DEST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
Appendix B: gather_on_test.sh
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Sample script to gather coverage data files on the test machine
|
||||||
|
(see 6b)::
|
||||||
|
|
||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
DEST=$1
|
||||||
|
GCDA=/sys/kernel/debug/gcov
|
||||||
|
|
||||||
|
if [ -z "$DEST" ] ; then
|
||||||
|
echo "Usage: $0 <output.tar.gz>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEMPDIR=$(mktemp -d)
|
||||||
|
echo Collecting data..
|
||||||
|
find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
|
||||||
|
find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
|
||||||
|
find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
|
||||||
|
tar czf $DEST -C $TEMPDIR sys
|
||||||
|
rm -rf $TEMPDIR
|
||||||
|
|
||||||
|
echo "$DEST successfully created, copy to build system and unpack with:"
|
||||||
|
echo " tar xfz $DEST"
|
@@ -1,3 +1,5 @@
|
|||||||
|
.. highlight:: none
|
||||||
|
|
||||||
Debugging kernel and modules via gdb
|
Debugging kernel and modules via gdb
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
@@ -13,54 +15,58 @@ be transferred to the other gdb stubs as well.
|
|||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
o gdb 7.2+ (recommended: 7.4+) with python support enabled (typically true
|
- gdb 7.2+ (recommended: 7.4+) with python support enabled (typically true
|
||||||
for distributions)
|
for distributions)
|
||||||
|
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
-----
|
-----
|
||||||
|
|
||||||
o Create a virtual Linux machine for QEMU/KVM (see www.linux-kvm.org and
|
- Create a virtual Linux machine for QEMU/KVM (see www.linux-kvm.org and
|
||||||
www.qemu.org for more details). For cross-development,
|
www.qemu.org for more details). For cross-development,
|
||||||
http://landley.net/aboriginal/bin keeps a pool of machine images and
|
http://landley.net/aboriginal/bin keeps a pool of machine images and
|
||||||
toolchains that can be helpful to start from.
|
toolchains that can be helpful to start from.
|
||||||
|
|
||||||
o Build the kernel with CONFIG_GDB_SCRIPTS enabled, but leave
|
- Build the kernel with CONFIG_GDB_SCRIPTS enabled, but leave
|
||||||
CONFIG_DEBUG_INFO_REDUCED off. If your architecture supports
|
CONFIG_DEBUG_INFO_REDUCED off. If your architecture supports
|
||||||
CONFIG_FRAME_POINTER, keep it enabled.
|
CONFIG_FRAME_POINTER, keep it enabled.
|
||||||
|
|
||||||
o Install that kernel on the guest.
|
- Install that kernel on the guest.
|
||||||
|
|
||||||
Alternatively, QEMU allows to boot the kernel directly using -kernel,
|
Alternatively, QEMU allows to boot the kernel directly using -kernel,
|
||||||
-append, -initrd command line switches. This is generally only useful if
|
-append, -initrd command line switches. This is generally only useful if
|
||||||
you do not depend on modules. See QEMU documentation for more details on
|
you do not depend on modules. See QEMU documentation for more details on
|
||||||
this mode.
|
this mode.
|
||||||
|
|
||||||
o Enable the gdb stub of QEMU/KVM, either
|
- Enable the gdb stub of QEMU/KVM, either
|
||||||
|
|
||||||
- at VM startup time by appending "-s" to the QEMU command line
|
- at VM startup time by appending "-s" to the QEMU command line
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
- during runtime by issuing "gdbserver" from the QEMU monitor
|
- during runtime by issuing "gdbserver" from the QEMU monitor
|
||||||
console
|
console
|
||||||
|
|
||||||
o cd /path/to/linux-build
|
- cd /path/to/linux-build
|
||||||
|
|
||||||
o Start gdb: gdb vmlinux
|
- Start gdb: gdb vmlinux
|
||||||
|
|
||||||
Note: Some distros may restrict auto-loading of gdb scripts to known safe
|
Note: Some distros may restrict auto-loading of gdb scripts to known safe
|
||||||
directories. In case gdb reports to refuse loading vmlinux-gdb.py, add
|
directories. In case gdb reports to refuse loading vmlinux-gdb.py, add::
|
||||||
|
|
||||||
add-auto-load-safe-path /path/to/linux-build
|
add-auto-load-safe-path /path/to/linux-build
|
||||||
|
|
||||||
to ~/.gdbinit. See gdb help for more details.
|
to ~/.gdbinit. See gdb help for more details.
|
||||||
|
|
||||||
o Attach to the booted guest:
|
- Attach to the booted guest::
|
||||||
|
|
||||||
(gdb) target remote :1234
|
(gdb) target remote :1234
|
||||||
|
|
||||||
|
|
||||||
Examples of using the Linux-provided gdb helpers
|
Examples of using the Linux-provided gdb helpers
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
o Load module (and main kernel) symbols:
|
- Load module (and main kernel) symbols::
|
||||||
|
|
||||||
(gdb) lx-symbols
|
(gdb) lx-symbols
|
||||||
loading vmlinux
|
loading vmlinux
|
||||||
scanning for modules in /home/user/linux/build
|
scanning for modules in /home/user/linux/build
|
||||||
@@ -72,17 +78,20 @@ Examples of using the Linux-provided gdb helpers
|
|||||||
...
|
...
|
||||||
loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
|
loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
|
||||||
|
|
||||||
o Set a breakpoint on some not yet loaded module function, e.g.:
|
- Set a breakpoint on some not yet loaded module function, e.g.::
|
||||||
|
|
||||||
(gdb) b btrfs_init_sysfs
|
(gdb) b btrfs_init_sysfs
|
||||||
Function "btrfs_init_sysfs" not defined.
|
Function "btrfs_init_sysfs" not defined.
|
||||||
Make breakpoint pending on future shared library load? (y or [n]) y
|
Make breakpoint pending on future shared library load? (y or [n]) y
|
||||||
Breakpoint 1 (btrfs_init_sysfs) pending.
|
Breakpoint 1 (btrfs_init_sysfs) pending.
|
||||||
|
|
||||||
o Continue the target
|
- Continue the target::
|
||||||
|
|
||||||
(gdb) c
|
(gdb) c
|
||||||
|
|
||||||
o Load the module on the target and watch the symbols being loaded as well as
|
- Load the module on the target and watch the symbols being loaded as well as
|
||||||
the breakpoint hit:
|
the breakpoint hit::
|
||||||
|
|
||||||
loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko
|
loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko
|
||||||
loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko
|
loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko
|
||||||
loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko
|
loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko
|
||||||
@@ -91,7 +100,8 @@ Examples of using the Linux-provided gdb helpers
|
|||||||
Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36
|
Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36
|
||||||
36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
|
36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
|
||||||
|
|
||||||
o Dump the log buffer of the target kernel:
|
- Dump the log buffer of the target kernel::
|
||||||
|
|
||||||
(gdb) lx-dmesg
|
(gdb) lx-dmesg
|
||||||
[ 0.000000] Initializing cgroup subsys cpuset
|
[ 0.000000] Initializing cgroup subsys cpuset
|
||||||
[ 0.000000] Initializing cgroup subsys cpu
|
[ 0.000000] Initializing cgroup subsys cpu
|
||||||
@@ -102,19 +112,22 @@ Examples of using the Linux-provided gdb helpers
|
|||||||
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
|
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
|
||||||
....
|
....
|
||||||
|
|
||||||
o Examine fields of the current task struct:
|
- Examine fields of the current task struct::
|
||||||
|
|
||||||
(gdb) p $lx_current().pid
|
(gdb) p $lx_current().pid
|
||||||
$1 = 4998
|
$1 = 4998
|
||||||
(gdb) p $lx_current().comm
|
(gdb) p $lx_current().comm
|
||||||
$2 = "modprobe\000\000\000\000\000\000\000"
|
$2 = "modprobe\000\000\000\000\000\000\000"
|
||||||
|
|
||||||
o Make use of the per-cpu function for the current or a specified CPU:
|
- Make use of the per-cpu function for the current or a specified CPU::
|
||||||
|
|
||||||
(gdb) p $lx_per_cpu("runqueues").nr_running
|
(gdb) p $lx_per_cpu("runqueues").nr_running
|
||||||
$3 = 1
|
$3 = 1
|
||||||
(gdb) p $lx_per_cpu("runqueues", 2).nr_running
|
(gdb) p $lx_per_cpu("runqueues", 2).nr_running
|
||||||
$4 = 0
|
$4 = 0
|
||||||
|
|
||||||
o Dig into hrtimers using the container_of helper:
|
- Dig into hrtimers using the container_of helper::
|
||||||
|
|
||||||
(gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next
|
(gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next
|
||||||
(gdb) p *$container_of($next, "struct hrtimer", "node")
|
(gdb) p *$container_of($next, "struct hrtimer", "node")
|
||||||
$5 = {
|
$5 = {
|
||||||
@@ -144,7 +157,7 @@ List of commands and functions
|
|||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
The number of commands and convenience functions may evolve over the time,
|
The number of commands and convenience functions may evolve over the time,
|
||||||
this is just a snapshot of the initial version:
|
this is just a snapshot of the initial version::
|
||||||
|
|
||||||
(gdb) apropos lx
|
(gdb) apropos lx
|
||||||
function lx_current -- Return current task
|
function lx_current -- Return current task
|
173
Documentation/dev-tools/kasan.rst
Normal file
173
Documentation/dev-tools/kasan.rst
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
The Kernel Address Sanitizer (KASAN)
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
KernelAddressSANitizer (KASAN) is a dynamic memory error detector. It provides
|
||||||
|
a fast and comprehensive solution for finding use-after-free and out-of-bounds
|
||||||
|
bugs.
|
||||||
|
|
||||||
|
KASAN uses compile-time instrumentation for checking every memory access,
|
||||||
|
therefore you will need a GCC version 4.9.2 or later. GCC 5.0 or later is
|
||||||
|
required for detection of out-of-bounds accesses to stack or global variables.
|
||||||
|
|
||||||
|
Currently KASAN is supported only for the x86_64 and arm64 architectures.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
To enable KASAN configure kernel with::
|
||||||
|
|
||||||
|
CONFIG_KASAN = y
|
||||||
|
|
||||||
|
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline and
|
||||||
|
inline are compiler instrumentation types. The former produces smaller binary
|
||||||
|
the latter is 1.1 - 2 times faster. Inline instrumentation requires a GCC
|
||||||
|
version 5.0 or later.
|
||||||
|
|
||||||
|
KASAN works with both SLUB and SLAB memory allocators.
|
||||||
|
For better bug detection and nicer reporting, enable CONFIG_STACKTRACE.
|
||||||
|
|
||||||
|
To disable instrumentation for specific files or directories, add a line
|
||||||
|
similar to the following to the respective kernel Makefile:
|
||||||
|
|
||||||
|
- For a single file (e.g. main.o)::
|
||||||
|
|
||||||
|
KASAN_SANITIZE_main.o := n
|
||||||
|
|
||||||
|
- For all files in one directory::
|
||||||
|
|
||||||
|
KASAN_SANITIZE := n
|
||||||
|
|
||||||
|
Error reports
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A typical out of bounds access report looks like this::
|
||||||
|
|
||||||
|
==================================================================
|
||||||
|
BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
|
||||||
|
Write of size 1 by task modprobe/1689
|
||||||
|
=============================================================================
|
||||||
|
BUG kmalloc-128 (Not tainted): kasan error
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Disabling lock debugging due to kernel taint
|
||||||
|
INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
|
||||||
|
__slab_alloc+0x4b4/0x4f0
|
||||||
|
kmem_cache_alloc_trace+0x10b/0x190
|
||||||
|
kmalloc_oob_right+0x3d/0x75 [test_kasan]
|
||||||
|
init_module+0x9/0x47 [test_kasan]
|
||||||
|
do_one_initcall+0x99/0x200
|
||||||
|
load_module+0x2cb3/0x3b20
|
||||||
|
SyS_finit_module+0x76/0x80
|
||||||
|
system_call_fastpath+0x12/0x17
|
||||||
|
INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
|
||||||
|
INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
|
||||||
|
|
||||||
|
Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
|
||||||
|
Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||||
|
Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
|
||||||
|
Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........
|
||||||
|
Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
|
||||||
|
CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98
|
||||||
|
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
|
||||||
|
ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
|
||||||
|
ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
|
||||||
|
ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
|
||||||
|
Call Trace:
|
||||||
|
[<ffffffff81cc68ae>] dump_stack+0x46/0x58
|
||||||
|
[<ffffffff811fd848>] print_trailer+0xf8/0x160
|
||||||
|
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
||||||
|
[<ffffffff811ff0f5>] object_err+0x35/0x40
|
||||||
|
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||||
|
[<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
|
||||||
|
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
||||||
|
[<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
|
||||||
|
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
||||||
|
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
||||||
|
[<ffffffff8120a995>] __asan_store1+0x75/0xb0
|
||||||
|
[<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
|
||||||
|
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||||
|
[<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||||
|
[<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
|
||||||
|
[<ffffffff810002d9>] do_one_initcall+0x99/0x200
|
||||||
|
[<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
|
||||||
|
[<ffffffff81114f63>] load_module+0x2cb3/0x3b20
|
||||||
|
[<ffffffff8110fd70>] ? m_show+0x240/0x240
|
||||||
|
[<ffffffff81115f06>] SyS_finit_module+0x76/0x80
|
||||||
|
[<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
|
||||||
|
Memory state around the buggy address:
|
||||||
|
ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||||
|
ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
|
||||||
|
ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||||
|
ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||||
|
ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
|
||||||
|
>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
|
||||||
|
^
|
||||||
|
ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||||
|
ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||||
|
ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
|
||||||
|
ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||||
|
ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
The header of the report discribe what kind of bug happened and what kind of
|
||||||
|
access caused it. It's followed by the description of the accessed slub object
|
||||||
|
(see 'SLUB Debug output' section in Documentation/vm/slub.txt for details) and
|
||||||
|
the description of the accessed memory page.
|
||||||
|
|
||||||
|
In the last section the report shows memory state around the accessed address.
|
||||||
|
Reading this part requires some understanding of how KASAN works.
|
||||||
|
|
||||||
|
The state of each 8 aligned bytes of memory is encoded in one shadow byte.
|
||||||
|
Those 8 bytes can be accessible, partially accessible, freed or be a redzone.
|
||||||
|
We use the following encoding for each shadow byte: 0 means that all 8 bytes
|
||||||
|
of the corresponding memory region are accessible; number N (1 <= N <= 7) means
|
||||||
|
that the first N bytes are accessible, and other (8 - N) bytes are not;
|
||||||
|
any negative value indicates that the entire 8-byte word is inaccessible.
|
||||||
|
We use different negative values to distinguish between different kinds of
|
||||||
|
inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
|
||||||
|
|
||||||
|
In the report above the arrows point to the shadow byte 03, which means that
|
||||||
|
the accessed address is partially accessible.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation details
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
From a high level, our approach to memory error detection is similar to that
|
||||||
|
of kmemcheck: use shadow memory to record whether each byte of memory is safe
|
||||||
|
to access, and use compile-time instrumentation to check shadow memory on each
|
||||||
|
memory access.
|
||||||
|
|
||||||
|
AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
|
||||||
|
(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
|
||||||
|
offset to translate a memory address to its corresponding shadow address.
|
||||||
|
|
||||||
|
Here is the function which translates an address to its corresponding shadow
|
||||||
|
address::
|
||||||
|
|
||||||
|
static inline void *kasan_mem_to_shadow(const void *addr)
|
||||||
|
{
|
||||||
|
return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
|
||||||
|
+ KASAN_SHADOW_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
where ``KASAN_SHADOW_SCALE_SHIFT = 3``.
|
||||||
|
|
||||||
|
Compile-time instrumentation used for checking memory accesses. Compiler inserts
|
||||||
|
function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
|
||||||
|
access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
|
||||||
|
valid or not by checking corresponding shadow memory.
|
||||||
|
|
||||||
|
GCC 5.0 has possibility to perform inline instrumentation. Instead of making
|
||||||
|
function calls GCC directly inserts the code to check the shadow memory.
|
||||||
|
This option significantly enlarges kernel but it gives x1.1-x2 performance
|
||||||
|
boost over outline instrumented kernel.
|
@@ -12,38 +12,38 @@ To achieve this goal it does not collect coverage in soft/hard interrupts
|
|||||||
and instrumentation of some inherently non-deterministic parts of kernel is
|
and instrumentation of some inherently non-deterministic parts of kernel is
|
||||||
disbled (e.g. scheduler, locking).
|
disbled (e.g. scheduler, locking).
|
||||||
|
|
||||||
Usage:
|
Usage
|
||||||
======
|
-----
|
||||||
|
|
||||||
Configure kernel with:
|
Configure the kernel with::
|
||||||
|
|
||||||
CONFIG_KCOV=y
|
CONFIG_KCOV=y
|
||||||
|
|
||||||
CONFIG_KCOV requires gcc built on revision 231296 or later.
|
CONFIG_KCOV requires gcc built on revision 231296 or later.
|
||||||
Profiling data will only become accessible once debugfs has been mounted:
|
Profiling data will only become accessible once debugfs has been mounted::
|
||||||
|
|
||||||
mount -t debugfs none /sys/kernel/debug
|
mount -t debugfs none /sys/kernel/debug
|
||||||
|
|
||||||
The following program demonstrates kcov usage from within a test program:
|
The following program demonstrates kcov usage from within a test program::
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
|
#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
|
||||||
#define KCOV_ENABLE _IO('c', 100)
|
#define KCOV_ENABLE _IO('c', 100)
|
||||||
#define KCOV_DISABLE _IO('c', 101)
|
#define KCOV_DISABLE _IO('c', 101)
|
||||||
#define COVER_SIZE (64<<10)
|
#define COVER_SIZE (64<<10)
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
unsigned long *cover, n, i;
|
unsigned long *cover, n, i;
|
||||||
|
|
||||||
@@ -83,24 +83,24 @@ int main(int argc, char **argv)
|
|||||||
if (close(fd))
|
if (close(fd))
|
||||||
perror("close"), exit(1);
|
perror("close"), exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
After piping through addr2line output of the program looks as follows:
|
After piping through addr2line output of the program looks as follows::
|
||||||
|
|
||||||
SyS_read
|
SyS_read
|
||||||
fs/read_write.c:562
|
fs/read_write.c:562
|
||||||
__fdget_pos
|
__fdget_pos
|
||||||
fs/file.c:774
|
fs/file.c:774
|
||||||
__fget_light
|
__fget_light
|
||||||
fs/file.c:746
|
fs/file.c:746
|
||||||
__fget_light
|
__fget_light
|
||||||
fs/file.c:750
|
fs/file.c:750
|
||||||
__fget_light
|
__fget_light
|
||||||
fs/file.c:760
|
fs/file.c:760
|
||||||
__fdget_pos
|
__fdget_pos
|
||||||
fs/file.c:784
|
fs/file.c:784
|
||||||
SyS_read
|
SyS_read
|
||||||
fs/read_write.c:562
|
fs/read_write.c:562
|
||||||
|
|
||||||
If a program needs to collect coverage from several threads (independently),
|
If a program needs to collect coverage from several threads (independently),
|
||||||
it needs to open /sys/kernel/debug/kcov in each thread separately.
|
it needs to open /sys/kernel/debug/kcov in each thread separately.
|
733
Documentation/dev-tools/kmemcheck.rst
Normal file
733
Documentation/dev-tools/kmemcheck.rst
Normal file
@@ -0,0 +1,733 @@
|
|||||||
|
Getting started with kmemcheck
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Vegard Nossum <vegardno@ifi.uio.no>
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
kmemcheck is a debugging feature for the Linux Kernel. More specifically, it
|
||||||
|
is a dynamic checker that detects and warns about some uses of uninitialized
|
||||||
|
memory.
|
||||||
|
|
||||||
|
Userspace programmers might be familiar with Valgrind's memcheck. The main
|
||||||
|
difference between memcheck and kmemcheck is that memcheck works for userspace
|
||||||
|
programs only, and kmemcheck works for the kernel only. The implementations
|
||||||
|
are of course vastly different. Because of this, kmemcheck is not as accurate
|
||||||
|
as memcheck, but it turns out to be good enough in practice to discover real
|
||||||
|
programmer errors that the compiler is not able to find through static
|
||||||
|
analysis.
|
||||||
|
|
||||||
|
Enabling kmemcheck on a kernel will probably slow it down to the extent that
|
||||||
|
the machine will not be usable for normal workloads such as e.g. an
|
||||||
|
interactive desktop. kmemcheck will also cause the kernel to use about twice
|
||||||
|
as much memory as normal. For this reason, kmemcheck is strictly a debugging
|
||||||
|
feature.
|
||||||
|
|
||||||
|
|
||||||
|
Downloading
|
||||||
|
-----------
|
||||||
|
|
||||||
|
As of version 2.6.31-rc1, kmemcheck is included in the mainline kernel.
|
||||||
|
|
||||||
|
|
||||||
|
Configuring and compiling
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
kmemcheck only works for the x86 (both 32- and 64-bit) platform. A number of
|
||||||
|
configuration variables must have specific settings in order for the kmemcheck
|
||||||
|
menu to even appear in "menuconfig". These are:
|
||||||
|
|
||||||
|
- ``CONFIG_CC_OPTIMIZE_FOR_SIZE=n``
|
||||||
|
This option is located under "General setup" / "Optimize for size".
|
||||||
|
|
||||||
|
Without this, gcc will use certain optimizations that usually lead to
|
||||||
|
false positive warnings from kmemcheck. An example of this is a 16-bit
|
||||||
|
field in a struct, where gcc may load 32 bits, then discard the upper
|
||||||
|
16 bits. kmemcheck sees only the 32-bit load, and may trigger a
|
||||||
|
warning for the upper 16 bits (if they're uninitialized).
|
||||||
|
|
||||||
|
- ``CONFIG_SLAB=y`` or ``CONFIG_SLUB=y``
|
||||||
|
This option is located under "General setup" / "Choose SLAB
|
||||||
|
allocator".
|
||||||
|
|
||||||
|
- ``CONFIG_FUNCTION_TRACER=n``
|
||||||
|
This option is located under "Kernel hacking" / "Tracers" / "Kernel
|
||||||
|
Function Tracer"
|
||||||
|
|
||||||
|
When function tracing is compiled in, gcc emits a call to another
|
||||||
|
function at the beginning of every function. This means that when the
|
||||||
|
page fault handler is called, the ftrace framework will be called
|
||||||
|
before kmemcheck has had a chance to handle the fault. If ftrace then
|
||||||
|
modifies memory that was tracked by kmemcheck, the result is an
|
||||||
|
endless recursive page fault.
|
||||||
|
|
||||||
|
- ``CONFIG_DEBUG_PAGEALLOC=n``
|
||||||
|
This option is located under "Kernel hacking" / "Memory Debugging"
|
||||||
|
/ "Debug page memory allocations".
|
||||||
|
|
||||||
|
In addition, I highly recommend turning on ``CONFIG_DEBUG_INFO=y``. This is also
|
||||||
|
located under "Kernel hacking". With this, you will be able to get line number
|
||||||
|
information from the kmemcheck warnings, which is extremely valuable in
|
||||||
|
debugging a problem. This option is not mandatory, however, because it slows
|
||||||
|
down the compilation process and produces a much bigger kernel image.
|
||||||
|
|
||||||
|
Now the kmemcheck menu should be visible (under "Kernel hacking" / "Memory
|
||||||
|
Debugging" / "kmemcheck: trap use of uninitialized memory"). Here follows
|
||||||
|
a description of the kmemcheck configuration variables:
|
||||||
|
|
||||||
|
- ``CONFIG_KMEMCHECK``
|
||||||
|
This must be enabled in order to use kmemcheck at all...
|
||||||
|
|
||||||
|
- ``CONFIG_KMEMCHECK_``[``DISABLED`` | ``ENABLED`` | ``ONESHOT``]``_BY_DEFAULT``
|
||||||
|
This option controls the status of kmemcheck at boot-time. "Enabled"
|
||||||
|
will enable kmemcheck right from the start, "disabled" will boot the
|
||||||
|
kernel as normal (but with the kmemcheck code compiled in, so it can
|
||||||
|
be enabled at run-time after the kernel has booted), and "one-shot" is
|
||||||
|
a special mode which will turn kmemcheck off automatically after
|
||||||
|
detecting the first use of uninitialized memory.
|
||||||
|
|
||||||
|
If you are using kmemcheck to actively debug a problem, then you
|
||||||
|
probably want to choose "enabled" here.
|
||||||
|
|
||||||
|
The one-shot mode is mostly useful in automated test setups because it
|
||||||
|
can prevent floods of warnings and increase the chances of the machine
|
||||||
|
surviving in case something is really wrong. In other cases, the one-
|
||||||
|
shot mode could actually be counter-productive because it would turn
|
||||||
|
itself off at the very first error -- in the case of a false positive
|
||||||
|
too -- and this would come in the way of debugging the specific
|
||||||
|
problem you were interested in.
|
||||||
|
|
||||||
|
If you would like to use your kernel as normal, but with a chance to
|
||||||
|
enable kmemcheck in case of some problem, it might be a good idea to
|
||||||
|
choose "disabled" here. When kmemcheck is disabled, most of the run-
|
||||||
|
time overhead is not incurred, and the kernel will be almost as fast
|
||||||
|
as normal.
|
||||||
|
|
||||||
|
- ``CONFIG_KMEMCHECK_QUEUE_SIZE``
|
||||||
|
Select the maximum number of error reports to store in an internal
|
||||||
|
(fixed-size) buffer. Since errors can occur virtually anywhere and in
|
||||||
|
any context, we need a temporary storage area which is guaranteed not
|
||||||
|
to generate any other page faults when accessed. The queue will be
|
||||||
|
emptied as soon as a tasklet may be scheduled. If the queue is full,
|
||||||
|
new error reports will be lost.
|
||||||
|
|
||||||
|
The default value of 64 is probably fine. If some code produces more
|
||||||
|
than 64 errors within an irqs-off section, then the code is likely to
|
||||||
|
produce many, many more, too, and these additional reports seldom give
|
||||||
|
any more information (the first report is usually the most valuable
|
||||||
|
anyway).
|
||||||
|
|
||||||
|
This number might have to be adjusted if you are not using serial
|
||||||
|
console or similar to capture the kernel log. If you are using the
|
||||||
|
"dmesg" command to save the log, then getting a lot of kmemcheck
|
||||||
|
warnings might overflow the kernel log itself, and the earlier reports
|
||||||
|
will get lost in that way instead. Try setting this to 10 or so on
|
||||||
|
such a setup.
|
||||||
|
|
||||||
|
- ``CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT``
|
||||||
|
Select the number of shadow bytes to save along with each entry of the
|
||||||
|
error-report queue. These bytes indicate what parts of an allocation
|
||||||
|
are initialized, uninitialized, etc. and will be displayed when an
|
||||||
|
error is detected to help the debugging of a particular problem.
|
||||||
|
|
||||||
|
The number entered here is actually the logarithm of the number of
|
||||||
|
bytes that will be saved. So if you pick for example 5 here, kmemcheck
|
||||||
|
will save 2^5 = 32 bytes.
|
||||||
|
|
||||||
|
The default value should be fine for debugging most problems. It also
|
||||||
|
fits nicely within 80 columns.
|
||||||
|
|
||||||
|
- ``CONFIG_KMEMCHECK_PARTIAL_OK``
|
||||||
|
This option (when enabled) works around certain GCC optimizations that
|
||||||
|
produce 32-bit reads from 16-bit variables where the upper 16 bits are
|
||||||
|
thrown away afterwards.
|
||||||
|
|
||||||
|
The default value (enabled) is recommended. This may of course hide
|
||||||
|
some real errors, but disabling it would probably produce a lot of
|
||||||
|
false positives.
|
||||||
|
|
||||||
|
- ``CONFIG_KMEMCHECK_BITOPS_OK``
|
||||||
|
This option silences warnings that would be generated for bit-field
|
||||||
|
accesses where not all the bits are initialized at the same time. This
|
||||||
|
may also hide some real bugs.
|
||||||
|
|
||||||
|
This option is probably obsolete, or it should be replaced with
|
||||||
|
the kmemcheck-/bitfield-annotations for the code in question. The
|
||||||
|
default value is therefore fine.
|
||||||
|
|
||||||
|
Now compile the kernel as usual.
|
||||||
|
|
||||||
|
|
||||||
|
How to use
|
||||||
|
----------
|
||||||
|
|
||||||
|
Booting
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
First some information about the command-line options. There is only one
|
||||||
|
option specific to kmemcheck, and this is called "kmemcheck". It can be used
|
||||||
|
to override the default mode as chosen by the ``CONFIG_KMEMCHECK_*_BY_DEFAULT``
|
||||||
|
option. Its possible settings are:
|
||||||
|
|
||||||
|
- ``kmemcheck=0`` (disabled)
|
||||||
|
- ``kmemcheck=1`` (enabled)
|
||||||
|
- ``kmemcheck=2`` (one-shot mode)
|
||||||
|
|
||||||
|
If SLUB debugging has been enabled in the kernel, it may take precedence over
|
||||||
|
kmemcheck in such a way that the slab caches which are under SLUB debugging
|
||||||
|
will not be tracked by kmemcheck. In order to ensure that this doesn't happen
|
||||||
|
(even though it shouldn't by default), use SLUB's boot option ``slub_debug``,
|
||||||
|
like this: ``slub_debug=-``
|
||||||
|
|
||||||
|
In fact, this option may also be used for fine-grained control over SLUB vs.
|
||||||
|
kmemcheck. For example, if the command line includes
|
||||||
|
``kmemcheck=1 slub_debug=,dentry``, then SLUB debugging will be used only
|
||||||
|
for the "dentry" slab cache, and with kmemcheck tracking all the other
|
||||||
|
caches. This is advanced usage, however, and is not generally recommended.
|
||||||
|
|
||||||
|
|
||||||
|
Run-time enable/disable
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When the kernel has booted, it is possible to enable or disable kmemcheck at
|
||||||
|
run-time. WARNING: This feature is still experimental and may cause false
|
||||||
|
positive warnings to appear. Therefore, try not to use this. If you find that
|
||||||
|
it doesn't work properly (e.g. you see an unreasonable amount of warnings), I
|
||||||
|
will be happy to take bug reports.
|
||||||
|
|
||||||
|
Use the file ``/proc/sys/kernel/kmemcheck`` for this purpose, e.g.::
|
||||||
|
|
||||||
|
$ echo 0 > /proc/sys/kernel/kmemcheck # disables kmemcheck
|
||||||
|
|
||||||
|
The numbers are the same as for the ``kmemcheck=`` command-line option.
|
||||||
|
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
A typical report will look something like this::
|
||||||
|
|
||||||
|
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
||||||
|
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||||
|
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||||
|
^
|
||||||
|
|
||||||
|
Pid: 1856, comm: ntpdate Not tainted 2.6.29-rc5 #264 945P-A
|
||||||
|
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
||||||
|
RSP: 0018:ffff88003cdf7d98 EFLAGS: 00210002
|
||||||
|
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
||||||
|
RDX: ffff88003e5d6018 RSI: ffff88003e5d6024 RDI: ffff88003cdf7e84
|
||||||
|
RBP: ffff88003cdf7db8 R08: ffff88003e5d6000 R09: 0000000000000000
|
||||||
|
R10: 0000000000000080 R11: 0000000000000000 R12: 000000000000000e
|
||||||
|
R13: ffff88003cdf7e78 R14: ffff88003d530710 R15: ffff88003d5a98c8
|
||||||
|
FS: 0000000000000000(0000) GS:ffff880001982000(0063) knlGS:00000
|
||||||
|
CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033
|
||||||
|
CR2: ffff88003f806ea0 CR3: 000000003c036000 CR4: 00000000000006a0
|
||||||
|
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||||
|
DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
|
||||||
|
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
||||||
|
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
||||||
|
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
||||||
|
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
||||||
|
[<ffffffffffffffff>] 0xffffffffffffffff
|
||||||
|
|
||||||
|
The single most valuable information in this report is the RIP (or EIP on 32-
|
||||||
|
bit) value. This will help us pinpoint exactly which instruction that caused
|
||||||
|
the warning.
|
||||||
|
|
||||||
|
If your kernel was compiled with ``CONFIG_DEBUG_INFO=y``, then all we have to do
|
||||||
|
is give this address to the addr2line program, like this::
|
||||||
|
|
||||||
|
$ addr2line -e vmlinux -i ffffffff8104ede8
|
||||||
|
arch/x86/include/asm/string_64.h:12
|
||||||
|
include/asm-generic/siginfo.h:287
|
||||||
|
kernel/signal.c:380
|
||||||
|
kernel/signal.c:410
|
||||||
|
|
||||||
|
The "``-e vmlinux``" tells addr2line which file to look in. **IMPORTANT:**
|
||||||
|
This must be the vmlinux of the kernel that produced the warning in the
|
||||||
|
first place! If not, the line number information will almost certainly be
|
||||||
|
wrong.
|
||||||
|
|
||||||
|
The "``-i``" tells addr2line to also print the line numbers of inlined
|
||||||
|
functions. In this case, the flag was very important, because otherwise,
|
||||||
|
it would only have printed the first line, which is just a call to
|
||||||
|
``memcpy()``, which could be called from a thousand places in the kernel, and
|
||||||
|
is therefore not very useful. These inlined functions would not show up in
|
||||||
|
the stack trace above, simply because the kernel doesn't load the extra
|
||||||
|
debugging information. This technique can of course be used with ordinary
|
||||||
|
kernel oopses as well.
|
||||||
|
|
||||||
|
In this case, it's the caller of ``memcpy()`` that is interesting, and it can be
|
||||||
|
found in ``include/asm-generic/siginfo.h``, line 287::
|
||||||
|
|
||||||
|
281 static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
|
||||||
|
282 {
|
||||||
|
283 if (from->si_code < 0)
|
||||||
|
284 memcpy(to, from, sizeof(*to));
|
||||||
|
285 else
|
||||||
|
286 /* _sigchld is currently the largest know union member */
|
||||||
|
287 memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
|
||||||
|
288 }
|
||||||
|
|
||||||
|
Since this was a read (kmemcheck usually warns about reads only, though it can
|
||||||
|
warn about writes to unallocated or freed memory as well), it was probably the
|
||||||
|
"from" argument which contained some uninitialized bytes. Following the chain
|
||||||
|
of calls, we move upwards to see where "from" was allocated or initialized,
|
||||||
|
``kernel/signal.c``, line 380::
|
||||||
|
|
||||||
|
359 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
|
||||||
|
360 {
|
||||||
|
...
|
||||||
|
367 list_for_each_entry(q, &list->list, list) {
|
||||||
|
368 if (q->info.si_signo == sig) {
|
||||||
|
369 if (first)
|
||||||
|
370 goto still_pending;
|
||||||
|
371 first = q;
|
||||||
|
...
|
||||||
|
377 if (first) {
|
||||||
|
378 still_pending:
|
||||||
|
379 list_del_init(&first->list);
|
||||||
|
380 copy_siginfo(info, &first->info);
|
||||||
|
381 __sigqueue_free(first);
|
||||||
|
...
|
||||||
|
392 }
|
||||||
|
393 }
|
||||||
|
|
||||||
|
Here, it is ``&first->info`` that is being passed on to ``copy_siginfo()``. The
|
||||||
|
variable ``first`` was found on a list -- passed in as the second argument to
|
||||||
|
``collect_signal()``. We continue our journey through the stack, to figure out
|
||||||
|
where the item on "list" was allocated or initialized. We move to line 410::
|
||||||
|
|
||||||
|
395 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
|
||||||
|
396 siginfo_t *info)
|
||||||
|
397 {
|
||||||
|
...
|
||||||
|
410 collect_signal(sig, pending, info);
|
||||||
|
...
|
||||||
|
414 }
|
||||||
|
|
||||||
|
Now we need to follow the ``pending`` pointer, since that is being passed on to
|
||||||
|
``collect_signal()`` as ``list``. At this point, we've run out of lines from the
|
||||||
|
"addr2line" output. Not to worry, we just paste the next addresses from the
|
||||||
|
kmemcheck stack dump, i.e.::
|
||||||
|
|
||||||
|
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
||||||
|
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
||||||
|
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
||||||
|
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
||||||
|
|
||||||
|
$ addr2line -e vmlinux -i ffffffff8104f04e ffffffff81050bd8 \
|
||||||
|
ffffffff8100b87d ffffffff8100c7b5
|
||||||
|
kernel/signal.c:446
|
||||||
|
kernel/signal.c:1806
|
||||||
|
arch/x86/kernel/signal.c:805
|
||||||
|
arch/x86/kernel/signal.c:871
|
||||||
|
arch/x86/kernel/entry_64.S:694
|
||||||
|
|
||||||
|
Remember that since these addresses were found on the stack and not as the
|
||||||
|
RIP value, they actually point to the _next_ instruction (they are return
|
||||||
|
addresses). This becomes obvious when we look at the code for line 446::
|
||||||
|
|
||||||
|
422 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
||||||
|
423 {
|
||||||
|
...
|
||||||
|
431 signr = __dequeue_signal(&tsk->signal->shared_pending,
|
||||||
|
432 mask, info);
|
||||||
|
433 /*
|
||||||
|
434 * itimer signal ?
|
||||||
|
435 *
|
||||||
|
436 * itimers are process shared and we restart periodic
|
||||||
|
437 * itimers in the signal delivery path to prevent DoS
|
||||||
|
438 * attacks in the high resolution timer case. This is
|
||||||
|
439 * compliant with the old way of self restarting
|
||||||
|
440 * itimers, as the SIGALRM is a legacy signal and only
|
||||||
|
441 * queued once. Changing the restart behaviour to
|
||||||
|
442 * restart the timer in the signal dequeue path is
|
||||||
|
443 * reducing the timer noise on heavy loaded !highres
|
||||||
|
444 * systems too.
|
||||||
|
445 */
|
||||||
|
446 if (unlikely(signr == SIGALRM)) {
|
||||||
|
...
|
||||||
|
489 }
|
||||||
|
|
||||||
|
So instead of looking at 446, we should be looking at 431, which is the line
|
||||||
|
that executes just before 446. Here we see that what we are looking for is
|
||||||
|
``&tsk->signal->shared_pending``.
|
||||||
|
|
||||||
|
Our next task is now to figure out which function that puts items on this
|
||||||
|
``shared_pending`` list. A crude, but efficient tool, is ``git grep``::
|
||||||
|
|
||||||
|
$ git grep -n 'shared_pending' kernel/
|
||||||
|
...
|
||||||
|
kernel/signal.c:828: pending = group ? &t->signal->shared_pending : &t->pending;
|
||||||
|
kernel/signal.c:1339: pending = group ? &t->signal->shared_pending : &t->pending;
|
||||||
|
...
|
||||||
|
|
||||||
|
There were more results, but none of them were related to list operations,
|
||||||
|
and these were the only assignments. We inspect the line numbers more closely
|
||||||
|
and find that this is indeed where items are being added to the list::
|
||||||
|
|
||||||
|
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
||||||
|
817 int group)
|
||||||
|
818 {
|
||||||
|
...
|
||||||
|
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||||
|
...
|
||||||
|
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
||||||
|
852 (is_si_special(info) ||
|
||||||
|
853 info->si_code >= 0)));
|
||||||
|
854 if (q) {
|
||||||
|
855 list_add_tail(&q->list, &pending->list);
|
||||||
|
...
|
||||||
|
890 }
|
||||||
|
|
||||||
|
and::
|
||||||
|
|
||||||
|
1309 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
|
||||||
|
1310 {
|
||||||
|
....
|
||||||
|
1339 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||||
|
1340 list_add_tail(&q->list, &pending->list);
|
||||||
|
....
|
||||||
|
1347 }
|
||||||
|
|
||||||
|
In the first case, the list element we are looking for, ``q``, is being
|
||||||
|
returned from the function ``__sigqueue_alloc()``, which looks like an
|
||||||
|
allocation function. Let's take a look at it::
|
||||||
|
|
||||||
|
187 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
|
||||||
|
188 int override_rlimit)
|
||||||
|
189 {
|
||||||
|
190 struct sigqueue *q = NULL;
|
||||||
|
191 struct user_struct *user;
|
||||||
|
192
|
||||||
|
193 /*
|
||||||
|
194 * We won't get problems with the target's UID changing under us
|
||||||
|
195 * because changing it requires RCU be used, and if t != current, the
|
||||||
|
196 * caller must be holding the RCU readlock (by way of a spinlock) and
|
||||||
|
197 * we use RCU protection here
|
||||||
|
198 */
|
||||||
|
199 user = get_uid(__task_cred(t)->user);
|
||||||
|
200 atomic_inc(&user->sigpending);
|
||||||
|
201 if (override_rlimit ||
|
||||||
|
202 atomic_read(&user->sigpending) <=
|
||||||
|
203 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
|
||||||
|
204 q = kmem_cache_alloc(sigqueue_cachep, flags);
|
||||||
|
205 if (unlikely(q == NULL)) {
|
||||||
|
206 atomic_dec(&user->sigpending);
|
||||||
|
207 free_uid(user);
|
||||||
|
208 } else {
|
||||||
|
209 INIT_LIST_HEAD(&q->list);
|
||||||
|
210 q->flags = 0;
|
||||||
|
211 q->user = user;
|
||||||
|
212 }
|
||||||
|
213
|
||||||
|
214 return q;
|
||||||
|
215 }
|
||||||
|
|
||||||
|
We see that this function initializes ``q->list``, ``q->flags``, and
|
||||||
|
``q->user``. It seems that now is the time to look at the definition of
|
||||||
|
``struct sigqueue``, e.g.::
|
||||||
|
|
||||||
|
14 struct sigqueue {
|
||||||
|
15 struct list_head list;
|
||||||
|
16 int flags;
|
||||||
|
17 siginfo_t info;
|
||||||
|
18 struct user_struct *user;
|
||||||
|
19 };
|
||||||
|
|
||||||
|
And, you might remember, it was a ``memcpy()`` on ``&first->info`` that
|
||||||
|
caused the warning, so this makes perfect sense. It also seems reasonable
|
||||||
|
to assume that it is the caller of ``__sigqueue_alloc()`` that has the
|
||||||
|
responsibility of filling out (initializing) this member.
|
||||||
|
|
||||||
|
But just which fields of the struct were uninitialized? Let's look at
|
||||||
|
kmemcheck's report again::
|
||||||
|
|
||||||
|
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
||||||
|
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||||
|
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||||
|
^
|
||||||
|
|
||||||
|
These first two lines are the memory dump of the memory object itself, and
|
||||||
|
the shadow bytemap, respectively. The memory object itself is in this case
|
||||||
|
``&first->info``. Just beware that the start of this dump is NOT the start
|
||||||
|
of the object itself! The position of the caret (^) corresponds with the
|
||||||
|
address of the read (ffff88003e4a2024).
|
||||||
|
|
||||||
|
The shadow bytemap dump legend is as follows:
|
||||||
|
|
||||||
|
- i: initialized
|
||||||
|
- u: uninitialized
|
||||||
|
- a: unallocated (memory has been allocated by the slab layer, but has not
|
||||||
|
yet been handed off to anybody)
|
||||||
|
- f: freed (memory has been allocated by the slab layer, but has been freed
|
||||||
|
by the previous owner)
|
||||||
|
|
||||||
|
In order to figure out where (relative to the start of the object) the
|
||||||
|
uninitialized memory was located, we have to look at the disassembly. For
|
||||||
|
that, we'll need the RIP address again::
|
||||||
|
|
||||||
|
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
||||||
|
|
||||||
|
$ objdump -d --no-show-raw-insn vmlinux | grep -C 8 ffffffff8104ede8:
|
||||||
|
ffffffff8104edc8: mov %r8,0x8(%r8)
|
||||||
|
ffffffff8104edcc: test %r10d,%r10d
|
||||||
|
ffffffff8104edcf: js ffffffff8104ee88 <__dequeue_signal+0x168>
|
||||||
|
ffffffff8104edd5: mov %rax,%rdx
|
||||||
|
ffffffff8104edd8: mov $0xc,%ecx
|
||||||
|
ffffffff8104eddd: mov %r13,%rdi
|
||||||
|
ffffffff8104ede0: mov $0x30,%eax
|
||||||
|
ffffffff8104ede5: mov %rdx,%rsi
|
||||||
|
ffffffff8104ede8: rep movsl %ds:(%rsi),%es:(%rdi)
|
||||||
|
ffffffff8104edea: test $0x2,%al
|
||||||
|
ffffffff8104edec: je ffffffff8104edf0 <__dequeue_signal+0xd0>
|
||||||
|
ffffffff8104edee: movsw %ds:(%rsi),%es:(%rdi)
|
||||||
|
ffffffff8104edf0: test $0x1,%al
|
||||||
|
ffffffff8104edf2: je ffffffff8104edf5 <__dequeue_signal+0xd5>
|
||||||
|
ffffffff8104edf4: movsb %ds:(%rsi),%es:(%rdi)
|
||||||
|
ffffffff8104edf5: mov %r8,%rdi
|
||||||
|
ffffffff8104edf8: callq ffffffff8104de60 <__sigqueue_free>
|
||||||
|
|
||||||
|
As expected, it's the "``rep movsl``" instruction from the ``memcpy()``
|
||||||
|
that causes the warning. We know about ``REP MOVSL`` that it uses the register
|
||||||
|
``RCX`` to count the number of remaining iterations. By taking a look at the
|
||||||
|
register dump again (from the kmemcheck report), we can figure out how many
|
||||||
|
bytes were left to copy::
|
||||||
|
|
||||||
|
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
||||||
|
|
||||||
|
By looking at the disassembly, we also see that ``%ecx`` is being loaded
|
||||||
|
with the value ``$0xc`` just before (ffffffff8104edd8), so we are very
|
||||||
|
lucky. Keep in mind that this is the number of iterations, not bytes. And
|
||||||
|
since this is a "long" operation, we need to multiply by 4 to get the
|
||||||
|
number of bytes. So this means that the uninitialized value was encountered
|
||||||
|
at 4 * (0xc - 0x9) = 12 bytes from the start of the object.
|
||||||
|
|
||||||
|
We can now try to figure out which field of the "``struct siginfo``" that
|
||||||
|
was not initialized. This is the beginning of the struct::
|
||||||
|
|
||||||
|
40 typedef struct siginfo {
|
||||||
|
41 int si_signo;
|
||||||
|
42 int si_errno;
|
||||||
|
43 int si_code;
|
||||||
|
44
|
||||||
|
45 union {
|
||||||
|
..
|
||||||
|
92 } _sifields;
|
||||||
|
93 } siginfo_t;
|
||||||
|
|
||||||
|
On 64-bit, the int is 4 bytes long, so it must the union member that has
|
||||||
|
not been initialized. We can verify this using gdb::
|
||||||
|
|
||||||
|
$ gdb vmlinux
|
||||||
|
...
|
||||||
|
(gdb) p &((struct siginfo *) 0)->_sifields
|
||||||
|
$1 = (union {...} *) 0x10
|
||||||
|
|
||||||
|
Actually, it seems that the union member is located at offset 0x10 -- which
|
||||||
|
means that gcc has inserted 4 bytes of padding between the members ``si_code``
|
||||||
|
and ``_sifields``. We can now get a fuller picture of the memory dump::
|
||||||
|
|
||||||
|
_----------------------------=> si_code
|
||||||
|
/ _--------------------=> (padding)
|
||||||
|
| / _------------=> _sifields(._kill._pid)
|
||||||
|
| | / _----=> _sifields(._kill._uid)
|
||||||
|
| | | /
|
||||||
|
-------|-------|-------|-------|
|
||||||
|
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||||
|
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||||
|
|
||||||
|
This allows us to realize another important fact: ``si_code`` contains the
|
||||||
|
value 0x80. Remember that x86 is little endian, so the first 4 bytes
|
||||||
|
"80000000" are really the number 0x00000080. With a bit of research, we
|
||||||
|
find that this is actually the constant ``SI_KERNEL`` defined in
|
||||||
|
``include/asm-generic/siginfo.h``::
|
||||||
|
|
||||||
|
144 #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||||
|
|
||||||
|
This macro is used in exactly one place in the x86 kernel: In ``send_signal()``
|
||||||
|
in ``kernel/signal.c``::
|
||||||
|
|
||||||
|
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
||||||
|
817 int group)
|
||||||
|
818 {
|
||||||
|
...
|
||||||
|
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||||
|
...
|
||||||
|
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
||||||
|
852 (is_si_special(info) ||
|
||||||
|
853 info->si_code >= 0)));
|
||||||
|
854 if (q) {
|
||||||
|
855 list_add_tail(&q->list, &pending->list);
|
||||||
|
856 switch ((unsigned long) info) {
|
||||||
|
...
|
||||||
|
865 case (unsigned long) SEND_SIG_PRIV:
|
||||||
|
866 q->info.si_signo = sig;
|
||||||
|
867 q->info.si_errno = 0;
|
||||||
|
868 q->info.si_code = SI_KERNEL;
|
||||||
|
869 q->info.si_pid = 0;
|
||||||
|
870 q->info.si_uid = 0;
|
||||||
|
871 break;
|
||||||
|
...
|
||||||
|
890 }
|
||||||
|
|
||||||
|
Not only does this match with the ``.si_code`` member, it also matches the place
|
||||||
|
we found earlier when looking for where siginfo_t objects are enqueued on the
|
||||||
|
``shared_pending`` list.
|
||||||
|
|
||||||
|
So to sum up: It seems that it is the padding introduced by the compiler
|
||||||
|
between two struct fields that is uninitialized, and this gets reported when
|
||||||
|
we do a ``memcpy()`` on the struct. This means that we have identified a false
|
||||||
|
positive warning.
|
||||||
|
|
||||||
|
Normally, kmemcheck will not report uninitialized accesses in ``memcpy()`` calls
|
||||||
|
when both the source and destination addresses are tracked. (Instead, we copy
|
||||||
|
the shadow bytemap as well). In this case, the destination address clearly
|
||||||
|
was not tracked. We can dig a little deeper into the stack trace from above::
|
||||||
|
|
||||||
|
arch/x86/kernel/signal.c:805
|
||||||
|
arch/x86/kernel/signal.c:871
|
||||||
|
arch/x86/kernel/entry_64.S:694
|
||||||
|
|
||||||
|
And we clearly see that the destination siginfo object is located on the
|
||||||
|
stack::
|
||||||
|
|
||||||
|
782 static void do_signal(struct pt_regs *regs)
|
||||||
|
783 {
|
||||||
|
784 struct k_sigaction ka;
|
||||||
|
785 siginfo_t info;
|
||||||
|
...
|
||||||
|
804 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||||
|
...
|
||||||
|
854 }
|
||||||
|
|
||||||
|
And this ``&info`` is what eventually gets passed to ``copy_siginfo()`` as the
|
||||||
|
destination argument.
|
||||||
|
|
||||||
|
Now, even though we didn't find an actual error here, the example is still a
|
||||||
|
good one, because it shows how one would go about to find out what the report
|
||||||
|
was all about.
|
||||||
|
|
||||||
|
|
||||||
|
Annotating false positives
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There are a few different ways to make annotations in the source code that
|
||||||
|
will keep kmemcheck from checking and reporting certain allocations. Here
|
||||||
|
they are:
|
||||||
|
|
||||||
|
- ``__GFP_NOTRACK_FALSE_POSITIVE``
|
||||||
|
This flag can be passed to ``kmalloc()`` or ``kmem_cache_alloc()``
|
||||||
|
(therefore also to other functions that end up calling one of
|
||||||
|
these) to indicate that the allocation should not be tracked
|
||||||
|
because it would lead to a false positive report. This is a "big
|
||||||
|
hammer" way of silencing kmemcheck; after all, even if the false
|
||||||
|
positive pertains to particular field in a struct, for example, we
|
||||||
|
will now lose the ability to find (real) errors in other parts of
|
||||||
|
the same struct.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
/* No warnings will ever trigger on accessing any part of x */
|
||||||
|
x = kmalloc(sizeof *x, GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE);
|
||||||
|
|
||||||
|
- ``kmemcheck_bitfield_begin(name)``/``kmemcheck_bitfield_end(name)`` and
|
||||||
|
``kmemcheck_annotate_bitfield(ptr, name)``
|
||||||
|
The first two of these three macros can be used inside struct
|
||||||
|
definitions to signal, respectively, the beginning and end of a
|
||||||
|
bitfield. Additionally, this will assign the bitfield a name, which
|
||||||
|
is given as an argument to the macros.
|
||||||
|
|
||||||
|
Having used these markers, one can later use
|
||||||
|
kmemcheck_annotate_bitfield() at the point of allocation, to indicate
|
||||||
|
which parts of the allocation is part of a bitfield.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
kmemcheck_bitfield_begin(flags);
|
||||||
|
int flag_a:1;
|
||||||
|
int flag_b:1;
|
||||||
|
kmemcheck_bitfield_end(flags);
|
||||||
|
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct foo *x = kmalloc(sizeof *x);
|
||||||
|
|
||||||
|
/* No warnings will trigger on accessing the bitfield of x */
|
||||||
|
kmemcheck_annotate_bitfield(x, flags);
|
||||||
|
|
||||||
|
Note that ``kmemcheck_annotate_bitfield()`` can be used even before the
|
||||||
|
return value of ``kmalloc()`` is checked -- in other words, passing NULL
|
||||||
|
as the first argument is legal (and will do nothing).
|
||||||
|
|
||||||
|
|
||||||
|
Reporting errors
|
||||||
|
----------------
|
||||||
|
|
||||||
|
As we have seen, kmemcheck will produce false positive reports. Therefore, it
|
||||||
|
is not very wise to blindly post kmemcheck warnings to mailing lists and
|
||||||
|
maintainers. Instead, I encourage maintainers and developers to find errors
|
||||||
|
in their own code. If you get a warning, you can try to work around it, try
|
||||||
|
to figure out if it's a real error or not, or simply ignore it. Most
|
||||||
|
developers know their own code and will quickly and efficiently determine the
|
||||||
|
root cause of a kmemcheck report. This is therefore also the most efficient
|
||||||
|
way to work with kmemcheck.
|
||||||
|
|
||||||
|
That said, we (the kmemcheck maintainers) will always be on the lookout for
|
||||||
|
false positives that we can annotate and silence. So whatever you find,
|
||||||
|
please drop us a note privately! Kernel configs and steps to reproduce (if
|
||||||
|
available) are of course a great help too.
|
||||||
|
|
||||||
|
Happy hacking!
|
||||||
|
|
||||||
|
|
||||||
|
Technical description
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
kmemcheck works by marking memory pages non-present. This means that whenever
|
||||||
|
somebody attempts to access the page, a page fault is generated. The page
|
||||||
|
fault handler notices that the page was in fact only hidden, and so it calls
|
||||||
|
on the kmemcheck code to make further investigations.
|
||||||
|
|
||||||
|
When the investigations are completed, kmemcheck "shows" the page by marking
|
||||||
|
it present (as it would be under normal circumstances). This way, the
|
||||||
|
interrupted code can continue as usual.
|
||||||
|
|
||||||
|
But after the instruction has been executed, we should hide the page again, so
|
||||||
|
that we can catch the next access too! Now kmemcheck makes use of a debugging
|
||||||
|
feature of the processor, namely single-stepping. When the processor has
|
||||||
|
finished the one instruction that generated the memory access, a debug
|
||||||
|
exception is raised. From here, we simply hide the page again and continue
|
||||||
|
execution, this time with the single-stepping feature turned off.
|
||||||
|
|
||||||
|
kmemcheck requires some assistance from the memory allocator in order to work.
|
||||||
|
The memory allocator needs to
|
||||||
|
|
||||||
|
1. Tell kmemcheck about newly allocated pages and pages that are about to
|
||||||
|
be freed. This allows kmemcheck to set up and tear down the shadow memory
|
||||||
|
for the pages in question. The shadow memory stores the status of each
|
||||||
|
byte in the allocation proper, e.g. whether it is initialized or
|
||||||
|
uninitialized.
|
||||||
|
|
||||||
|
2. Tell kmemcheck which parts of memory should be marked uninitialized.
|
||||||
|
There are actually a few more states, such as "not yet allocated" and
|
||||||
|
"recently freed".
|
||||||
|
|
||||||
|
If a slab cache is set up using the SLAB_NOTRACK flag, it will never return
|
||||||
|
memory that can take page faults because of kmemcheck.
|
||||||
|
|
||||||
|
If a slab cache is NOT set up using the SLAB_NOTRACK flag, callers can still
|
||||||
|
request memory with the __GFP_NOTRACK or __GFP_NOTRACK_FALSE_POSITIVE flags.
|
||||||
|
This does not prevent the page faults from occurring, however, but marks the
|
||||||
|
object in question as being initialized so that no warnings will ever be
|
||||||
|
produced for this object.
|
||||||
|
|
||||||
|
Currently, the SLAB and SLUB allocators are supported by kmemcheck.
|
@@ -1,15 +1,12 @@
|
|||||||
Kernel Memory Leak Detector
|
Kernel Memory Leak Detector
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
Kmemleak provides a way of detecting possible kernel memory leaks in a
|
Kmemleak provides a way of detecting possible kernel memory leaks in a
|
||||||
way similar to a tracing garbage collector
|
way similar to a tracing garbage collector
|
||||||
(https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
|
(https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
|
||||||
with the difference that the orphan objects are not freed but only
|
with the difference that the orphan objects are not freed but only
|
||||||
reported via /sys/kernel/debug/kmemleak. A similar method is used by the
|
reported via /sys/kernel/debug/kmemleak. A similar method is used by the
|
||||||
Valgrind tool (memcheck --leak-check) to detect the memory leaks in
|
Valgrind tool (``memcheck --leak-check``) to detect the memory leaks in
|
||||||
user-space applications.
|
user-space applications.
|
||||||
Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze, ppc, mips, s390, metag and tile.
|
Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze, ppc, mips, s390, metag and tile.
|
||||||
|
|
||||||
@@ -19,20 +16,20 @@ Usage
|
|||||||
CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
|
CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
|
||||||
thread scans the memory every 10 minutes (by default) and prints the
|
thread scans the memory every 10 minutes (by default) and prints the
|
||||||
number of new unreferenced objects found. To display the details of all
|
number of new unreferenced objects found. To display the details of all
|
||||||
the possible memory leaks:
|
the possible memory leaks::
|
||||||
|
|
||||||
# mount -t debugfs nodev /sys/kernel/debug/
|
# mount -t debugfs nodev /sys/kernel/debug/
|
||||||
# cat /sys/kernel/debug/kmemleak
|
# cat /sys/kernel/debug/kmemleak
|
||||||
|
|
||||||
To trigger an intermediate memory scan:
|
To trigger an intermediate memory scan::
|
||||||
|
|
||||||
# echo scan > /sys/kernel/debug/kmemleak
|
# echo scan > /sys/kernel/debug/kmemleak
|
||||||
|
|
||||||
To clear the list of all current possible memory leaks:
|
To clear the list of all current possible memory leaks::
|
||||||
|
|
||||||
# echo clear > /sys/kernel/debug/kmemleak
|
# echo clear > /sys/kernel/debug/kmemleak
|
||||||
|
|
||||||
New leaks will then come up upon reading /sys/kernel/debug/kmemleak
|
New leaks will then come up upon reading ``/sys/kernel/debug/kmemleak``
|
||||||
again.
|
again.
|
||||||
|
|
||||||
Note that the orphan objects are listed in the order they were allocated
|
Note that the orphan objects are listed in the order they were allocated
|
||||||
@@ -40,22 +37,31 @@ and one object at the beginning of the list may cause other subsequent
|
|||||||
objects to be reported as orphan.
|
objects to be reported as orphan.
|
||||||
|
|
||||||
Memory scanning parameters can be modified at run-time by writing to the
|
Memory scanning parameters can be modified at run-time by writing to the
|
||||||
/sys/kernel/debug/kmemleak file. The following parameters are supported:
|
``/sys/kernel/debug/kmemleak`` file. The following parameters are supported:
|
||||||
|
|
||||||
off - disable kmemleak (irreversible)
|
- off
|
||||||
stack=on - enable the task stacks scanning (default)
|
disable kmemleak (irreversible)
|
||||||
stack=off - disable the tasks stacks scanning
|
- stack=on
|
||||||
scan=on - start the automatic memory scanning thread (default)
|
enable the task stacks scanning (default)
|
||||||
scan=off - stop the automatic memory scanning thread
|
- stack=off
|
||||||
scan=<secs> - set the automatic memory scanning period in seconds
|
disable the tasks stacks scanning
|
||||||
|
- scan=on
|
||||||
|
start the automatic memory scanning thread (default)
|
||||||
|
- scan=off
|
||||||
|
stop the automatic memory scanning thread
|
||||||
|
- scan=<secs>
|
||||||
|
set the automatic memory scanning period in seconds
|
||||||
(default 600, 0 to stop the automatic scanning)
|
(default 600, 0 to stop the automatic scanning)
|
||||||
scan - trigger a memory scan
|
- scan
|
||||||
clear - clear list of current memory leak suspects, done by
|
trigger a memory scan
|
||||||
|
- clear
|
||||||
|
clear list of current memory leak suspects, done by
|
||||||
marking all current reported unreferenced objects grey,
|
marking all current reported unreferenced objects grey,
|
||||||
or free all kmemleak objects if kmemleak has been disabled.
|
or free all kmemleak objects if kmemleak has been disabled.
|
||||||
dump=<addr> - dump information about the object found at <addr>
|
- dump=<addr>
|
||||||
|
dump information about the object found at <addr>
|
||||||
|
|
||||||
Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
|
Kmemleak can also be disabled at boot-time by passing ``kmemleak=off`` on
|
||||||
the kernel command line.
|
the kernel command line.
|
||||||
|
|
||||||
Memory may be allocated or freed before kmemleak is initialised and
|
Memory may be allocated or freed before kmemleak is initialised and
|
||||||
@@ -63,13 +69,14 @@ these actions are stored in an early log buffer. The size of this buffer
|
|||||||
is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
|
is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
|
||||||
|
|
||||||
If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
|
If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
|
||||||
disabled by default. Passing "kmemleak=on" on the kernel command
|
disabled by default. Passing ``kmemleak=on`` on the kernel command
|
||||||
line enables the function.
|
line enables the function.
|
||||||
|
|
||||||
Basic Algorithm
|
Basic Algorithm
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
The memory allocations via kmalloc, vmalloc, kmem_cache_alloc and
|
The memory allocations via :c:func:`kmalloc`, :c:func:`vmalloc`,
|
||||||
|
:c:func:`kmem_cache_alloc` and
|
||||||
friends are traced and the pointers, together with additional
|
friends are traced and the pointers, together with additional
|
||||||
information like size and stack trace, are stored in a rbtree.
|
information like size and stack trace, are stored in a rbtree.
|
||||||
The corresponding freeing function calls are tracked and the pointers
|
The corresponding freeing function calls are tracked and the pointers
|
||||||
@@ -113,13 +120,13 @@ when doing development. To work around these situations you can use the
|
|||||||
you can find new unreferenced objects; this should help with testing
|
you can find new unreferenced objects; this should help with testing
|
||||||
specific sections of code.
|
specific sections of code.
|
||||||
|
|
||||||
To test a critical section on demand with a clean kmemleak do:
|
To test a critical section on demand with a clean kmemleak do::
|
||||||
|
|
||||||
# echo clear > /sys/kernel/debug/kmemleak
|
# echo clear > /sys/kernel/debug/kmemleak
|
||||||
... test your kernel or modules ...
|
... test your kernel or modules ...
|
||||||
# echo scan > /sys/kernel/debug/kmemleak
|
# echo scan > /sys/kernel/debug/kmemleak
|
||||||
|
|
||||||
Then as usual to get your report with:
|
Then as usual to get your report with::
|
||||||
|
|
||||||
# cat /sys/kernel/debug/kmemleak
|
# cat /sys/kernel/debug/kmemleak
|
||||||
|
|
||||||
@@ -131,7 +138,7 @@ disabled by the user or due to an fatal error, internal kmemleak objects
|
|||||||
won't be freed when kmemleak is disabled, and those objects may occupy
|
won't be freed when kmemleak is disabled, and those objects may occupy
|
||||||
a large part of physical memory.
|
a large part of physical memory.
|
||||||
|
|
||||||
In this situation, you may reclaim memory with:
|
In this situation, you may reclaim memory with::
|
||||||
|
|
||||||
# echo clear > /sys/kernel/debug/kmemleak
|
# echo clear > /sys/kernel/debug/kmemleak
|
||||||
|
|
||||||
@@ -140,20 +147,20 @@ Kmemleak API
|
|||||||
|
|
||||||
See the include/linux/kmemleak.h header for the functions prototype.
|
See the include/linux/kmemleak.h header for the functions prototype.
|
||||||
|
|
||||||
kmemleak_init - initialize kmemleak
|
- ``kmemleak_init`` - initialize kmemleak
|
||||||
kmemleak_alloc - notify of a memory block allocation
|
- ``kmemleak_alloc`` - notify of a memory block allocation
|
||||||
kmemleak_alloc_percpu - notify of a percpu memory block allocation
|
- ``kmemleak_alloc_percpu`` - notify of a percpu memory block allocation
|
||||||
kmemleak_free - notify of a memory block freeing
|
- ``kmemleak_free`` - notify of a memory block freeing
|
||||||
kmemleak_free_part - notify of a partial memory block freeing
|
- ``kmemleak_free_part`` - notify of a partial memory block freeing
|
||||||
kmemleak_free_percpu - notify of a percpu memory block freeing
|
- ``kmemleak_free_percpu`` - notify of a percpu memory block freeing
|
||||||
kmemleak_update_trace - update object allocation stack trace
|
- ``kmemleak_update_trace`` - update object allocation stack trace
|
||||||
kmemleak_not_leak - mark an object as not a leak
|
- ``kmemleak_not_leak`` - mark an object as not a leak
|
||||||
kmemleak_ignore - do not scan or report an object as leak
|
- ``kmemleak_ignore`` - do not scan or report an object as leak
|
||||||
kmemleak_scan_area - add scan areas inside a memory block
|
- ``kmemleak_scan_area`` - add scan areas inside a memory block
|
||||||
kmemleak_no_scan - do not scan a memory block
|
- ``kmemleak_no_scan`` - do not scan a memory block
|
||||||
kmemleak_erase - erase an old value in a pointer variable
|
- ``kmemleak_erase`` - erase an old value in a pointer variable
|
||||||
kmemleak_alloc_recursive - as kmemleak_alloc but checks the recursiveness
|
- ``kmemleak_alloc_recursive`` - as kmemleak_alloc but checks the recursiveness
|
||||||
kmemleak_free_recursive - as kmemleak_free but checks the recursiveness
|
- ``kmemleak_free_recursive`` - as kmemleak_free but checks the recursiveness
|
||||||
|
|
||||||
Dealing with false positives/negatives
|
Dealing with false positives/negatives
|
||||||
--------------------------------------
|
--------------------------------------
|
@@ -1,11 +1,20 @@
|
|||||||
Copyright 2004 Linus Torvalds
|
.. Copyright 2004 Linus Torvalds
|
||||||
Copyright 2004 Pavel Machek <pavel@ucw.cz>
|
.. Copyright 2004 Pavel Machek <pavel@ucw.cz>
|
||||||
Copyright 2006 Bob Copeland <me@bobcopeland.com>
|
.. Copyright 2006 Bob Copeland <me@bobcopeland.com>
|
||||||
|
|
||||||
|
Sparse
|
||||||
|
======
|
||||||
|
|
||||||
|
Sparse is a semantic checker for C programs; it can be used to find a
|
||||||
|
number of potential problems with kernel code. See
|
||||||
|
https://lwn.net/Articles/689907/ for an overview of sparse; this document
|
||||||
|
contains some kernel-specific sparse information.
|
||||||
|
|
||||||
|
|
||||||
Using sparse for typechecking
|
Using sparse for typechecking
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
-----------------------------
|
||||||
|
|
||||||
"__bitwise" is a type attribute, so you have to do something like this:
|
"__bitwise" is a type attribute, so you have to do something like this::
|
||||||
|
|
||||||
typedef int __bitwise pm_request_t;
|
typedef int __bitwise pm_request_t;
|
||||||
|
|
||||||
@@ -20,13 +29,13 @@ but in this case we really _do_ want to force the conversion). And because
|
|||||||
the enum values are all the same type, now "enum pm_request" will be that
|
the enum values are all the same type, now "enum pm_request" will be that
|
||||||
type too.
|
type too.
|
||||||
|
|
||||||
And with gcc, all the __bitwise/__force stuff goes away, and it all ends
|
And with gcc, all the "__bitwise"/"__force stuff" goes away, and it all
|
||||||
up looking just like integers to gcc.
|
ends up looking just like integers to gcc.
|
||||||
|
|
||||||
Quite frankly, you don't need the enum there. The above all really just
|
Quite frankly, you don't need the enum there. The above all really just
|
||||||
boils down to one special "int __bitwise" type.
|
boils down to one special "int __bitwise" type.
|
||||||
|
|
||||||
So the simpler way is to just do
|
So the simpler way is to just do::
|
||||||
|
|
||||||
typedef int __bitwise pm_request_t;
|
typedef int __bitwise pm_request_t;
|
||||||
|
|
||||||
@@ -50,7 +59,7 @@ __bitwise - noisy stuff; in particular, __le*/__be* are that. We really
|
|||||||
don't want to drown in noise unless we'd explicitly asked for it.
|
don't want to drown in noise unless we'd explicitly asked for it.
|
||||||
|
|
||||||
Using sparse for lock checking
|
Using sparse for lock checking
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
------------------------------
|
||||||
|
|
||||||
The following macros are undefined for gcc and defined during a sparse
|
The following macros are undefined for gcc and defined during a sparse
|
||||||
run to use the "context" tracking feature of sparse, applied to
|
run to use the "context" tracking feature of sparse, applied to
|
||||||
@@ -69,22 +78,22 @@ annotation is needed. The tree annotations above are for cases where
|
|||||||
sparse would otherwise report a context imbalance.
|
sparse would otherwise report a context imbalance.
|
||||||
|
|
||||||
Getting sparse
|
Getting sparse
|
||||||
~~~~~~~~~~~~~~
|
--------------
|
||||||
|
|
||||||
You can get latest released versions from the Sparse homepage at
|
You can get latest released versions from the Sparse homepage at
|
||||||
https://sparse.wiki.kernel.org/index.php/Main_Page
|
https://sparse.wiki.kernel.org/index.php/Main_Page
|
||||||
|
|
||||||
Alternatively, you can get snapshots of the latest development version
|
Alternatively, you can get snapshots of the latest development version
|
||||||
of sparse using git to clone..
|
of sparse using git to clone::
|
||||||
|
|
||||||
git://git.kernel.org/pub/scm/devel/sparse/sparse.git
|
git://git.kernel.org/pub/scm/devel/sparse/sparse.git
|
||||||
|
|
||||||
DaveJ has hourly generated tarballs of the git tree available at..
|
DaveJ has hourly generated tarballs of the git tree available at::
|
||||||
|
|
||||||
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
|
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
|
||||||
|
|
||||||
|
|
||||||
Once you have it, just do
|
Once you have it, just do::
|
||||||
|
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
@@ -92,7 +101,7 @@ Once you have it, just do
|
|||||||
as a regular user, and it will install sparse in your ~/bin directory.
|
as a regular user, and it will install sparse in your ~/bin directory.
|
||||||
|
|
||||||
Using sparse
|
Using sparse
|
||||||
~~~~~~~~~~~~
|
------------
|
||||||
|
|
||||||
Do a kernel make with "make C=1" to run sparse on all the C files that get
|
Do a kernel make with "make C=1" to run sparse on all the C files that get
|
||||||
recompiled, or use "make C=2" to run sparse on the files whether they need to
|
recompiled, or use "make C=2" to run sparse on the files whether they need to
|
||||||
@@ -101,7 +110,7 @@ have already built it.
|
|||||||
|
|
||||||
The optional make variable CF can be used to pass arguments to sparse. The
|
The optional make variable CF can be used to pass arguments to sparse. The
|
||||||
build system passes -Wbitwise to sparse automatically. To perform endianness
|
build system passes -Wbitwise to sparse automatically. To perform endianness
|
||||||
checks, you may define __CHECK_ENDIAN__:
|
checks, you may define __CHECK_ENDIAN__::
|
||||||
|
|
||||||
make C=2 CF="-D__CHECK_ENDIAN__"
|
make C=2 CF="-D__CHECK_ENDIAN__"
|
||||||
|
|
25
Documentation/dev-tools/tools.rst
Normal file
25
Documentation/dev-tools/tools.rst
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
================================
|
||||||
|
Development tools for the kernel
|
||||||
|
================================
|
||||||
|
|
||||||
|
This document is a collection of documents about development tools that can
|
||||||
|
be used to work on the kernel. For now, the documents have been pulled
|
||||||
|
together without any significant effot to integrate them into a coherent
|
||||||
|
whole; patches welcome!
|
||||||
|
|
||||||
|
.. class:: toc-title
|
||||||
|
|
||||||
|
Table of contents
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
coccinelle
|
||||||
|
sparse
|
||||||
|
kcov
|
||||||
|
gcov
|
||||||
|
kasan
|
||||||
|
ubsan
|
||||||
|
kmemleak
|
||||||
|
kmemcheck
|
||||||
|
gdb-kernel-debugging
|
@@ -1,7 +1,5 @@
|
|||||||
Undefined Behavior Sanitizer - UBSAN
|
The Undefined Behavior Sanitizer - UBSAN
|
||||||
|
========================================
|
||||||
Overview
|
|
||||||
--------
|
|
||||||
|
|
||||||
UBSAN is a runtime undefined behaviour checker.
|
UBSAN is a runtime undefined behaviour checker.
|
||||||
|
|
||||||
@@ -10,11 +8,13 @@ Compiler inserts code that perform certain kinds of checks before operations
|
|||||||
that may cause UB. If check fails (i.e. UB detected) __ubsan_handle_*
|
that may cause UB. If check fails (i.e. UB detected) __ubsan_handle_*
|
||||||
function called to print error message.
|
function called to print error message.
|
||||||
|
|
||||||
GCC has that feature since 4.9.x [1] (see -fsanitize=undefined option and
|
GCC has that feature since 4.9.x [1_] (see ``-fsanitize=undefined`` option and
|
||||||
its suboptions). GCC 5.x has more checkers implemented [2].
|
its suboptions). GCC 5.x has more checkers implemented [2_].
|
||||||
|
|
||||||
Report example
|
Report example
|
||||||
---------------
|
--------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
UBSAN: Undefined behaviour in ../include/linux/bitops.h:110:33
|
UBSAN: Undefined behaviour in ../include/linux/bitops.h:110:33
|
||||||
@@ -47,28 +47,32 @@ Report example
|
|||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
||||||
To enable UBSAN configure kernel with:
|
To enable UBSAN configure kernel with::
|
||||||
|
|
||||||
CONFIG_UBSAN=y
|
CONFIG_UBSAN=y
|
||||||
|
|
||||||
and to check the entire kernel:
|
and to check the entire kernel::
|
||||||
|
|
||||||
CONFIG_UBSAN_SANITIZE_ALL=y
|
CONFIG_UBSAN_SANITIZE_ALL=y
|
||||||
|
|
||||||
To enable instrumentation for specific files or directories, add a line
|
To enable instrumentation for specific files or directories, add a line
|
||||||
similar to the following to the respective kernel Makefile:
|
similar to the following to the respective kernel Makefile:
|
||||||
|
|
||||||
For a single file (e.g. main.o):
|
- For a single file (e.g. main.o)::
|
||||||
|
|
||||||
UBSAN_SANITIZE_main.o := y
|
UBSAN_SANITIZE_main.o := y
|
||||||
|
|
||||||
For all files in one directory:
|
- For all files in one directory::
|
||||||
|
|
||||||
UBSAN_SANITIZE := y
|
UBSAN_SANITIZE := y
|
||||||
|
|
||||||
To exclude files from being instrumented even if
|
To exclude files from being instrumented even if
|
||||||
CONFIG_UBSAN_SANITIZE_ALL=y, use:
|
``CONFIG_UBSAN_SANITIZE_ALL=y``, use::
|
||||||
|
|
||||||
UBSAN_SANITIZE_main.o := n
|
UBSAN_SANITIZE_main.o := n
|
||||||
and:
|
|
||||||
|
and::
|
||||||
|
|
||||||
UBSAN_SANITIZE := n
|
UBSAN_SANITIZE := n
|
||||||
|
|
||||||
Detection of unaligned accesses controlled through the separate option -
|
Detection of unaligned accesses controlled through the separate option -
|
||||||
@@ -80,5 +84,5 @@ reports.
|
|||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
|
|
||||||
[1] - https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html
|
.. _1: https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html
|
||||||
[2] - https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
|
.. _2: https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
|
65
Documentation/devicetree/bindings/media/atmel-isc.txt
Normal file
65
Documentation/devicetree/bindings/media/atmel-isc.txt
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
Atmel Image Sensor Controller (ISC)
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
Required properties for ISC:
|
||||||
|
- compatible
|
||||||
|
Must be "atmel,sama5d2-isc".
|
||||||
|
- reg
|
||||||
|
Physical base address and length of the registers set for the device.
|
||||||
|
- interrupts
|
||||||
|
Should contain IRQ line for the ISC.
|
||||||
|
- clocks
|
||||||
|
List of clock specifiers, corresponding to entries in
|
||||||
|
the clock-names property;
|
||||||
|
Please refer to clock-bindings.txt.
|
||||||
|
- clock-names
|
||||||
|
Required elements: "hclock", "iscck", "gck".
|
||||||
|
- #clock-cells
|
||||||
|
Should be 0.
|
||||||
|
- clock-output-names
|
||||||
|
Should be "isc-mck".
|
||||||
|
- pinctrl-names, pinctrl-0
|
||||||
|
Please refer to pinctrl-bindings.txt.
|
||||||
|
|
||||||
|
ISC supports a single port node with parallel bus. It should contain one
|
||||||
|
'port' child node with child 'endpoint' node. Please refer to the bindings
|
||||||
|
defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
isc: isc@f0008000 {
|
||||||
|
compatible = "atmel,sama5d2-isc";
|
||||||
|
reg = <0xf0008000 0x4000>;
|
||||||
|
interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>;
|
||||||
|
clocks = <&isc_clk>, <&iscck>, <&isc_gclk>;
|
||||||
|
clock-names = "hclock", "iscck", "gck";
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clock-output-names = "isc-mck";
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>;
|
||||||
|
|
||||||
|
port {
|
||||||
|
isc_0: endpoint {
|
||||||
|
remote-endpoint = <&ov7740_0>;
|
||||||
|
hsync-active = <1>;
|
||||||
|
vsync-active = <0>;
|
||||||
|
pclk-sample = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c1: i2c@fc028000 {
|
||||||
|
ov7740: camera@21 {
|
||||||
|
compatible = "ovti,ov7740";
|
||||||
|
reg = <0x21>;
|
||||||
|
clocks = <&isc>;
|
||||||
|
clock-names = "xvclk";
|
||||||
|
assigned-clocks = <&isc>;
|
||||||
|
assigned-clock-rates = <24000000>;
|
||||||
|
|
||||||
|
port {
|
||||||
|
ov7740_0: endpoint {
|
||||||
|
remote-endpoint = <&isc_0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
@@ -16,9 +16,10 @@ Required properties:
|
|||||||
- clocks : list of clock specifiers, corresponding to entries in
|
- clocks : list of clock specifiers, corresponding to entries in
|
||||||
clock-names property;
|
clock-names property;
|
||||||
- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1"
|
- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1"
|
||||||
"mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "uart",
|
"mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "gicisp",
|
||||||
"ispdiv0", "ispdiv1", "mcuispdiv0", "mcuispdiv1", "aclk200",
|
"pwm_isp", "mcuctl_isp", "uart", "ispdiv0", "ispdiv1",
|
||||||
"div_aclk200", "aclk400mcuisp", "div_aclk400mcuisp" entries,
|
"mcuispdiv0", "mcuispdiv1", "aclk200", "div_aclk200",
|
||||||
|
"aclk400mcuisp", "div_aclk400mcuisp" entries,
|
||||||
matching entries in the clocks property.
|
matching entries in the clocks property.
|
||||||
pmu subnode
|
pmu subnode
|
||||||
-----------
|
-----------
|
||||||
|
19
Documentation/devicetree/bindings/media/i2c/ad5820.txt
Normal file
19
Documentation/devicetree/bindings/media/i2c/ad5820.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
* Analog Devices AD5820 autofocus coil
|
||||||
|
|
||||||
|
Required Properties:
|
||||||
|
|
||||||
|
- compatible: Must contain "adi,ad5820"
|
||||||
|
|
||||||
|
- reg: I2C slave address
|
||||||
|
|
||||||
|
- VANA-supply: supply of voltage for VANA pin
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
ad5820: coil@c {
|
||||||
|
compatible = "adi,ad5820";
|
||||||
|
reg = <0x0c>;
|
||||||
|
|
||||||
|
VANA-supply = <&vaux4>;
|
||||||
|
};
|
||||||
|
|
@@ -15,6 +15,11 @@ Required Properties :
|
|||||||
"adi,adv7282"
|
"adi,adv7282"
|
||||||
"adi,adv7282-m"
|
"adi,adv7282-m"
|
||||||
|
|
||||||
|
Optional Properties :
|
||||||
|
- powerdown-gpios: reference to the GPIO connected to the powerdown pin,
|
||||||
|
if any.
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
i2c0@1c22000 {
|
i2c0@1c22000 {
|
||||||
|
@@ -7,12 +7,14 @@ conversion of AXI transactions in order to reduce the memory bandwidth.
|
|||||||
|
|
||||||
There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP
|
There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP
|
||||||
for FDP (FCPF). Their configuration and behaviour depend on the module they
|
for FDP (FCPF). Their configuration and behaviour depend on the module they
|
||||||
are paired with. These DT bindings currently support the FCPV only.
|
are paired with. These DT bindings currently support the FCPV and FCPF.
|
||||||
|
|
||||||
- compatible: Must be one or more of the following
|
- compatible: Must be one or more of the following
|
||||||
|
|
||||||
- "renesas,r8a7795-fcpv" for R8A7795 (R-Car H3) compatible 'FCP for VSP'
|
- "renesas,r8a7795-fcpv" for R8A7795 (R-Car H3) compatible 'FCP for VSP'
|
||||||
|
- "renesas,r8a7795-fcpf" for R8A7795 (R-Car H3) compatible 'FCP for FDP'
|
||||||
- "renesas,fcpv" for generic compatible 'FCP for VSP'
|
- "renesas,fcpv" for generic compatible 'FCP for VSP'
|
||||||
|
- "renesas,fcpf" for generic compatible 'FCP for FDP'
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
SoC-specific version corresponding to the platform first, followed by the
|
SoC-specific version corresponding to the platform first, followed by the
|
||||||
@@ -21,6 +23,10 @@ are paired with. These DT bindings currently support the FCPV only.
|
|||||||
- reg: the register base and size for the device registers
|
- reg: the register base and size for the device registers
|
||||||
- clocks: Reference to the functional clock
|
- clocks: Reference to the functional clock
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- power-domains : power-domain property defined with a power domain specifier
|
||||||
|
to respective power domain.
|
||||||
|
|
||||||
|
|
||||||
Device node example
|
Device node example
|
||||||
-------------------
|
-------------------
|
||||||
@@ -29,4 +35,5 @@ Device node example
|
|||||||
compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
|
compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
|
||||||
reg = <0 0xfea2f000 0 0x200>;
|
reg = <0 0xfea2f000 0 0x200>;
|
||||||
clocks = <&cpg CPG_MOD 602>;
|
clocks = <&cpg CPG_MOD 602>;
|
||||||
|
power-domains = <&sysc R8A7795_PD_A3VP>;
|
||||||
};
|
};
|
||||||
|
24
Documentation/devicetree/bindings/media/st,st-hva.txt
Normal file
24
Documentation/devicetree/bindings/media/st,st-hva.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
st-hva: multi-format video encoder for STMicroelectronics SoC.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "st,st-hva".
|
||||||
|
- reg: HVA physical address location and length, esram address location and
|
||||||
|
length.
|
||||||
|
- reg-names: names of the registers listed in registers property in the same
|
||||||
|
order.
|
||||||
|
- interrupts: HVA interrupt number.
|
||||||
|
- clocks: from common clock binding: handle hardware IP needed clocks, the
|
||||||
|
number of clocks may depend on the SoC type.
|
||||||
|
See ../clock/clock-bindings.txt for details.
|
||||||
|
- clock-names: names of the clocks listed in clocks property in the same order.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
hva@8c85000{
|
||||||
|
compatible = "st,st-hva";
|
||||||
|
reg = <0x8c85000 0x400>, <0x6000000 0x40000>;
|
||||||
|
reg-names = "hva_registers", "hva_esram";
|
||||||
|
interrupts = <GIC_SPI 58 IRQ_TYPE_NONE>,
|
||||||
|
<GIC_SPI 59 IRQ_TYPE_NONE>;
|
||||||
|
clock-names = "clk_hva";
|
||||||
|
clocks = <&clk_s_c0_flexgen CLK_HVA>;
|
||||||
|
};
|
25
Documentation/devicetree/bindings/media/stih-cec.txt
Normal file
25
Documentation/devicetree/bindings/media/stih-cec.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
STMicroelectronics STIH4xx HDMI CEC driver
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : value should be "st,stih-cec"
|
||||||
|
- reg : Physical base address of the IP registers and length of memory
|
||||||
|
mapped region.
|
||||||
|
- clocks : from common clock binding: handle to HDMI CEC clock
|
||||||
|
- interrupts : HDMI CEC interrupt number to the CPU.
|
||||||
|
- pinctrl-names: Contains only one value - "default"
|
||||||
|
- pinctrl-0: Specifies the pin control groups used for CEC hardware.
|
||||||
|
- resets: Reference to a reset controller
|
||||||
|
|
||||||
|
Example for STIH407:
|
||||||
|
|
||||||
|
sti-cec@094a087c {
|
||||||
|
compatible = "st,stih-cec";
|
||||||
|
reg = <0x94a087c 0x64>;
|
||||||
|
clocks = <&clk_sysin>;
|
||||||
|
clock-names = "cec-clk";
|
||||||
|
interrupts = <GIC_SPI 140 IRQ_TYPE_NONE>;
|
||||||
|
interrupt-names = "cec-irq";
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_cec0_default>;
|
||||||
|
resets = <&softreset STIH407_LPM_SOFTRESET>;
|
||||||
|
};
|
7
Documentation/docutils.conf
Normal file
7
Documentation/docutils.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# -*- coding: utf-8 mode: conf-colon -*-
|
||||||
|
#
|
||||||
|
# docutils configuration file
|
||||||
|
# http://docutils.sourceforge.net/docs/user/config.html
|
||||||
|
|
||||||
|
[general]
|
||||||
|
halt_level: severe
|
120
Documentation/driver-api/basics.rst
Normal file
120
Documentation/driver-api/basics.rst
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
Driver Basics
|
||||||
|
=============
|
||||||
|
|
||||||
|
Driver Entry and Exit points
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/init.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
Atomic and pointer manipulation
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: arch/x86/include/asm/atomic.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
Delaying, scheduling, and timer routines
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/sched.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/sched/core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/sched/cpupri.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/sched/fair.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/completion.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/time/timer.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Wait queues and Wake events
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/wait.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/sched/wait.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
High-resolution timers
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/ktime.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/hrtimer.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/time/hrtimer.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Workqueues and Kevents
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/workqueue.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/workqueue.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Internal Functions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/exit.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/signal.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/kthread.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/kthread.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Kernel objects manipulation
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: lib/kobject.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Kernel utility functions
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/kernel.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/printk/printk.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/panic.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/sys.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/rcu/srcu.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/rcu/tree.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/rcu/tree_plugin.h
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: kernel/rcu/update.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Device Resource Management
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/devres.c
|
||||||
|
:export:
|
||||||
|
|
62
Documentation/driver-api/frame-buffer.rst
Normal file
62
Documentation/driver-api/frame-buffer.rst
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
Frame Buffer Library
|
||||||
|
====================
|
||||||
|
|
||||||
|
The frame buffer drivers depend heavily on four data structures. These
|
||||||
|
structures are declared in include/linux/fb.h. They are fb_info,
|
||||||
|
fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs. The last
|
||||||
|
three can be made available to and from userland.
|
||||||
|
|
||||||
|
fb_info defines the current state of a particular video card. Inside
|
||||||
|
fb_info, there exists a fb_ops structure which is a collection of
|
||||||
|
needed functions to make fbdev and fbcon work. fb_info is only visible
|
||||||
|
to the kernel.
|
||||||
|
|
||||||
|
fb_var_screeninfo is used to describe the features of a video card
|
||||||
|
that are user defined. With fb_var_screeninfo, things such as depth
|
||||||
|
and the resolution may be defined.
|
||||||
|
|
||||||
|
The next structure is fb_fix_screeninfo. This defines the properties
|
||||||
|
of a card that are created when a mode is set and can't be changed
|
||||||
|
otherwise. A good example of this is the start of the frame buffer
|
||||||
|
memory. This "locks" the address of the frame buffer memory, so that it
|
||||||
|
cannot be changed or moved.
|
||||||
|
|
||||||
|
The last structure is fb_monospecs. In the old API, there was little
|
||||||
|
importance for fb_monospecs. This allowed for forbidden things such as
|
||||||
|
setting a mode of 800x600 on a fix frequency monitor. With the new API,
|
||||||
|
fb_monospecs prevents such things, and if used correctly, can prevent a
|
||||||
|
monitor from being cooked. fb_monospecs will not be useful until
|
||||||
|
kernels 2.5.x.
|
||||||
|
|
||||||
|
Frame Buffer Memory
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/video/fbdev/core/fbmem.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Frame Buffer Colormap
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/video/fbdev/core/fbcmap.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Frame Buffer Video Mode Database
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/video/fbdev/core/modedb.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/video/fbdev/core/modedb.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Frame Buffer Macintosh Video Mode Database
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/video/fbdev/macmodes.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Frame Buffer Fonts
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Refer to the file lib/fonts/fonts.c for more information.
|
||||||
|
|
88
Documentation/driver-api/hsi.rst
Normal file
88
Documentation/driver-api/hsi.rst
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
High Speed Synchronous Serial Interface (HSI)
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
---------------
|
||||||
|
|
||||||
|
High Speed Syncronous Interface (HSI) is a fullduplex, low latency protocol,
|
||||||
|
that is optimized for die-level interconnect between an Application Processor
|
||||||
|
and a Baseband chipset. It has been specified by the MIPI alliance in 2003 and
|
||||||
|
implemented by multiple vendors since then.
|
||||||
|
|
||||||
|
The HSI interface supports full duplex communication over multiple channels
|
||||||
|
(typically 8) and is capable of reaching speeds up to 200 Mbit/s.
|
||||||
|
|
||||||
|
The serial protocol uses two signals, DATA and FLAG as combined data and clock
|
||||||
|
signals and an additional READY signal for flow control. An additional WAKE
|
||||||
|
signal can be used to wakeup the chips from standby modes. The signals are
|
||||||
|
commonly prefixed by AC for signals going from the application die to the
|
||||||
|
cellular die and CA for signals going the other way around.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+------------+ +---------------+
|
||||||
|
| Cellular | | Application |
|
||||||
|
| Die | | Die |
|
||||||
|
| | - - - - - - CAWAKE - - - - - - >| |
|
||||||
|
| T|------------ CADATA ------------>|R |
|
||||||
|
| X|------------ CAFLAG ------------>|X |
|
||||||
|
| |<----------- ACREADY ------------| |
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
| |< - - - - - ACWAKE - - - - - - -| |
|
||||||
|
| R|<----------- ACDATA -------------|T |
|
||||||
|
| X|<----------- ACFLAG -------------|X |
|
||||||
|
| |------------ CAREADY ----------->| |
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
+------------+ +---------------+
|
||||||
|
|
||||||
|
HSI Subsystem in Linux
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
In the Linux kernel the hsi subsystem is supposed to be used for HSI devices.
|
||||||
|
The hsi subsystem contains drivers for hsi controllers including support for
|
||||||
|
multi-port controllers and provides a generic API for using the HSI ports.
|
||||||
|
|
||||||
|
It also contains HSI client drivers, which make use of the generic API to
|
||||||
|
implement a protocol used on the HSI interface. These client drivers can
|
||||||
|
use an arbitrary number of channels.
|
||||||
|
|
||||||
|
hsi-char Device
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Each port automatically registers a generic client driver called hsi_char,
|
||||||
|
which provides a charecter device for userspace representing the HSI port.
|
||||||
|
It can be used to communicate via HSI from userspace. Userspace may
|
||||||
|
configure the hsi_char device using the following ioctl commands:
|
||||||
|
|
||||||
|
HSC_RESET
|
||||||
|
flush the HSI port
|
||||||
|
|
||||||
|
HSC_SET_PM
|
||||||
|
enable or disable the client.
|
||||||
|
|
||||||
|
HSC_SEND_BREAK
|
||||||
|
send break
|
||||||
|
|
||||||
|
HSC_SET_RX
|
||||||
|
set RX configuration
|
||||||
|
|
||||||
|
HSC_GET_RX
|
||||||
|
get RX configuration
|
||||||
|
|
||||||
|
HSC_SET_TX
|
||||||
|
set TX configuration
|
||||||
|
|
||||||
|
HSC_GET_TX
|
||||||
|
get TX configuration
|
||||||
|
|
||||||
|
The kernel HSI API
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/hsi/hsi.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/hsi/hsi_core.c
|
||||||
|
:export:
|
||||||
|
|
46
Documentation/driver-api/i2c.rst
Normal file
46
Documentation/driver-api/i2c.rst
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
I\ :sup:`2`\ C and SMBus Subsystem
|
||||||
|
==================================
|
||||||
|
|
||||||
|
I\ :sup:`2`\ C (or without fancy typography, "I2C") is an acronym for
|
||||||
|
the "Inter-IC" bus, a simple bus protocol which is widely used where low
|
||||||
|
data rate communications suffice. Since it's also a licensed trademark,
|
||||||
|
some vendors use another name (such as "Two-Wire Interface", TWI) for
|
||||||
|
the same bus. I2C only needs two signals (SCL for clock, SDA for data),
|
||||||
|
conserving board real estate and minimizing signal quality issues. Most
|
||||||
|
I2C devices use seven bit addresses, and bus speeds of up to 400 kHz;
|
||||||
|
there's a high speed extension (3.4 MHz) that's not yet found wide use.
|
||||||
|
I2C is a multi-master bus; open drain signaling is used to arbitrate
|
||||||
|
between masters, as well as to handshake and to synchronize clocks from
|
||||||
|
slower clients.
|
||||||
|
|
||||||
|
The Linux I2C programming interfaces support only the master side of bus
|
||||||
|
interactions, not the slave side. The programming interface is
|
||||||
|
structured around two kinds of driver, and two kinds of device. An I2C
|
||||||
|
"Adapter Driver" abstracts the controller hardware; it binds to a
|
||||||
|
physical device (perhaps a PCI device or platform_device) and exposes a
|
||||||
|
:c:type:`struct i2c_adapter <i2c_adapter>` representing each
|
||||||
|
I2C bus segment it manages. On each I2C bus segment will be I2C devices
|
||||||
|
represented by a :c:type:`struct i2c_client <i2c_client>`.
|
||||||
|
Those devices will be bound to a :c:type:`struct i2c_driver
|
||||||
|
<i2c_driver>`, which should follow the standard Linux driver
|
||||||
|
model. (At this writing, a legacy model is more widely used.) There are
|
||||||
|
functions to perform various I2C protocol operations; at this writing
|
||||||
|
all such functions are usable only from task context.
|
||||||
|
|
||||||
|
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
||||||
|
systems are also I2C conformant. The electrical constraints are tighter
|
||||||
|
for SMBus, and it standardizes particular protocol messages and idioms.
|
||||||
|
Controllers that support I2C can also support most SMBus operations, but
|
||||||
|
SMBus controllers don't support all the protocol options that an I2C
|
||||||
|
controller will. There are functions to perform various SMBus protocol
|
||||||
|
operations, either using I2C primitives or by issuing SMBus commands to
|
||||||
|
i2c_adapter devices which don't support those I2C operations.
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/i2c.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/i2c/i2c-boardinfo.c
|
||||||
|
:functions: i2c_register_board_info
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/i2c/i2c-core.c
|
||||||
|
:export:
|
26
Documentation/driver-api/index.rst
Normal file
26
Documentation/driver-api/index.rst
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
========================================
|
||||||
|
The Linux driver implementer's API guide
|
||||||
|
========================================
|
||||||
|
|
||||||
|
The kernel offers a wide variety of interfaces to support the development
|
||||||
|
of device drivers. This document is an only somewhat organized collection
|
||||||
|
of some of those interfaces — it will hopefully get better over time! The
|
||||||
|
available subsections can be seen below.
|
||||||
|
|
||||||
|
.. class:: toc-title
|
||||||
|
|
||||||
|
Table of contents
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
basics
|
||||||
|
infrastructure
|
||||||
|
message-based
|
||||||
|
sound
|
||||||
|
frame-buffer
|
||||||
|
input
|
||||||
|
spi
|
||||||
|
i2c
|
||||||
|
hsi
|
||||||
|
miscellaneous
|
169
Documentation/driver-api/infrastructure.rst
Normal file
169
Documentation/driver-api/infrastructure.rst
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
Device drivers infrastructure
|
||||||
|
=============================
|
||||||
|
|
||||||
|
The Basic Device Driver-Model Structures
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/device.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
Device Drivers Base
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/init.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/driver.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/syscore.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/class.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/node.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/firmware_class.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/transport_class.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/dd.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/platform_device.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/platform.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/bus.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Buffer Sharing and Synchronization
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
The dma-buf subsystem provides the framework for sharing buffers for
|
||||||
|
hardware (DMA) access across multiple device drivers and subsystems, and
|
||||||
|
for synchronizing asynchronous hardware access.
|
||||||
|
|
||||||
|
This is used, for example, by drm "prime" multi-GPU support, but is of
|
||||||
|
course not limited to GPU use cases.
|
||||||
|
|
||||||
|
The three main components of this are: (1) dma-buf, representing a
|
||||||
|
sg_table and exposed to userspace as a file descriptor to allow passing
|
||||||
|
between devices, (2) fence, which provides a mechanism to signal when
|
||||||
|
one device as finished access, and (3) reservation, which manages the
|
||||||
|
shared or exclusive fence(s) associated with the buffer.
|
||||||
|
|
||||||
|
dma-buf
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/dma-buf.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/dma-buf.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
reservation
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/reservation.c
|
||||||
|
:doc: Reservation Object Overview
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/reservation.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/reservation.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
fence
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/fence.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/fence.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/seqno-fence.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/seqno-fence.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/fence-array.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/fence-array.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/reservation.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/reservation.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/dma-buf/sync_file.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/sync_file.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
Device Drivers DMA Management
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/dma-coherent.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/dma-mapping.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Device Drivers Power Management
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/base/power/main.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Device Drivers ACPI Support
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/acpi/scan.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/acpi/scan.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
Device drivers PnP support
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/pnp/core.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/pnp/card.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/pnp/driver.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/pnp/manager.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/pnp/support.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Userspace IO devices
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/uio/uio.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/uio_driver.h
|
||||||
|
:internal:
|
||||||
|
|
51
Documentation/driver-api/input.rst
Normal file
51
Documentation/driver-api/input.rst
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
Input Subsystem
|
||||||
|
===============
|
||||||
|
|
||||||
|
Input core
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/input.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/input/input.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/input/ff-core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/input/ff-memless.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Multitouch Library
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/input/mt.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/input/input-mt.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Polled input devices
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/input-polldev.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/input/input-polldev.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Matrix keyboards/keypads
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/input/matrix_keypad.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
Sparse keymap support
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/input/sparse-keymap.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/input/sparse-keymap.c
|
||||||
|
:export:
|
||||||
|
|
12
Documentation/driver-api/message-based.rst
Normal file
12
Documentation/driver-api/message-based.rst
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Message-based devices
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Fusion message devices
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/message/fusion/mptbase.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/message/fusion/mptscsih.c
|
||||||
|
:export:
|
||||||
|
|
50
Documentation/driver-api/miscellaneous.rst
Normal file
50
Documentation/driver-api/miscellaneous.rst
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
Parallel Port Devices
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/parport.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/parport/ieee1284.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/parport/share.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/parport/daisy.c
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
16x50 UART Driver
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/tty/serial/serial_core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/tty/serial/8250/8250_core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
Pulse-Width Modulation (PWM)
|
||||||
|
============================
|
||||||
|
|
||||||
|
Pulse-width modulation is a modulation technique primarily used to
|
||||||
|
control power supplied to electrical devices.
|
||||||
|
|
||||||
|
The PWM framework provides an abstraction for providers and consumers of
|
||||||
|
PWM signals. A controller that provides one or more PWM signals is
|
||||||
|
registered as :c:type:`struct pwm_chip <pwm_chip>`. Providers
|
||||||
|
are expected to embed this structure in a driver-specific structure.
|
||||||
|
This structure contains fields that describe a particular chip.
|
||||||
|
|
||||||
|
A chip exposes one or more PWM signal sources, each of which exposed as
|
||||||
|
a :c:type:`struct pwm_device <pwm_device>`. Operations can be
|
||||||
|
performed on PWM devices to control the period, duty cycle, polarity and
|
||||||
|
active state of the signal.
|
||||||
|
|
||||||
|
Note that PWM devices are exclusive resources: they can always only be
|
||||||
|
used by one consumer at a time.
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/pwm.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/pwm/core.c
|
||||||
|
:export:
|
||||||
|
|
54
Documentation/driver-api/sound.rst
Normal file
54
Documentation/driver-api/sound.rst
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
Sound Devices
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. kernel-doc:: include/sound/core.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/sound_core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/sound/pcm.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/pcm.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/device.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/info.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/rawmidi.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/sound.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/memory.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/pcm_memory.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/init.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/isadma.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/control.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/pcm_lib.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/hwdep.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/pcm_native.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: sound/core/memalloc.c
|
||||||
|
:export:
|
||||||
|
|
53
Documentation/driver-api/spi.rst
Normal file
53
Documentation/driver-api/spi.rst
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
Serial Peripheral Interface (SPI)
|
||||||
|
=================================
|
||||||
|
|
||||||
|
SPI is the "Serial Peripheral Interface", widely used with embedded
|
||||||
|
systems because it is a simple and efficient interface: basically a
|
||||||
|
multiplexed shift register. Its three signal wires hold a clock (SCK,
|
||||||
|
often in the range of 1-20 MHz), a "Master Out, Slave In" (MOSI) data
|
||||||
|
line, and a "Master In, Slave Out" (MISO) data line. SPI is a full
|
||||||
|
duplex protocol; for each bit shifted out the MOSI line (one per clock)
|
||||||
|
another is shifted in on the MISO line. Those bits are assembled into
|
||||||
|
words of various sizes on the way to and from system memory. An
|
||||||
|
additional chipselect line is usually active-low (nCS); four signals are
|
||||||
|
normally used for each peripheral, plus sometimes an interrupt.
|
||||||
|
|
||||||
|
The SPI bus facilities listed here provide a generalized interface to
|
||||||
|
declare SPI busses and devices, manage them according to the standard
|
||||||
|
Linux driver model, and perform input/output operations. At this time,
|
||||||
|
only "master" side interfaces are supported, where Linux talks to SPI
|
||||||
|
peripherals and does not implement such a peripheral itself. (Interfaces
|
||||||
|
to support implementing SPI slaves would necessarily look different.)
|
||||||
|
|
||||||
|
The programming interface is structured around two kinds of driver, and
|
||||||
|
two kinds of device. A "Controller Driver" abstracts the controller
|
||||||
|
hardware, which may be as simple as a set of GPIO pins or as complex as
|
||||||
|
a pair of FIFOs connected to dual DMA engines on the other side of the
|
||||||
|
SPI shift register (maximizing throughput). Such drivers bridge between
|
||||||
|
whatever bus they sit on (often the platform bus) and SPI, and expose
|
||||||
|
the SPI side of their device as a :c:type:`struct spi_master
|
||||||
|
<spi_master>`. SPI devices are children of that master,
|
||||||
|
represented as a :c:type:`struct spi_device <spi_device>` and
|
||||||
|
manufactured from :c:type:`struct spi_board_info
|
||||||
|
<spi_board_info>` descriptors which are usually provided by
|
||||||
|
board-specific initialization code. A :c:type:`struct spi_driver
|
||||||
|
<spi_driver>` is called a "Protocol Driver", and is bound to a
|
||||||
|
spi_device using normal driver model calls.
|
||||||
|
|
||||||
|
The I/O model is a set of queued messages. Protocol drivers submit one
|
||||||
|
or more :c:type:`struct spi_message <spi_message>` objects,
|
||||||
|
which are processed and completed asynchronously. (There are synchronous
|
||||||
|
wrappers, however.) Messages are built from one or more
|
||||||
|
:c:type:`struct spi_transfer <spi_transfer>` objects, each of
|
||||||
|
which wraps a full duplex SPI transfer. A variety of protocol tweaking
|
||||||
|
options are needed, because different chips adopt very different
|
||||||
|
policies for how they use the bits transferred with SPI.
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/spi/spi.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/spi/spi.c
|
||||||
|
:functions: spi_register_board_info
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/spi/spi.c
|
||||||
|
:export:
|
@@ -50,7 +50,7 @@ Attributes of devices can be exported by a device driver through sysfs.
|
|||||||
Please see Documentation/filesystems/sysfs.txt for more information
|
Please see Documentation/filesystems/sysfs.txt for more information
|
||||||
on how sysfs works.
|
on how sysfs works.
|
||||||
|
|
||||||
As explained in Documentation/kobject.txt, device attributes must be be
|
As explained in Documentation/kobject.txt, device attributes must be
|
||||||
created before the KOBJ_ADD uevent is generated. The only way to realize
|
created before the KOBJ_ADD uevent is generated. The only way to realize
|
||||||
that is by defining an attribute group.
|
that is by defining an attribute group.
|
||||||
|
|
||||||
|
@@ -145,7 +145,7 @@ Table 1-1: Process specific entries in /proc
|
|||||||
symbol the task is blocked in - or "0" if not blocked.
|
symbol the task is blocked in - or "0" if not blocked.
|
||||||
pagemap Page table
|
pagemap Page table
|
||||||
stack Report full stack trace, enable via CONFIG_STACKTRACE
|
stack Report full stack trace, enable via CONFIG_STACKTRACE
|
||||||
smaps a extension based on maps, showing the memory consumption of
|
smaps an extension based on maps, showing the memory consumption of
|
||||||
each mapping and flags associated with it
|
each mapping and flags associated with it
|
||||||
numa_maps an extension based on maps, showing the memory locality and
|
numa_maps an extension based on maps, showing the memory locality and
|
||||||
binding policy as well as mem usage (in pages) of each mapping.
|
binding policy as well as mem usage (in pages) of each mapping.
|
||||||
|
@@ -1,257 +0,0 @@
|
|||||||
Using gcov with the Linux kernel
|
|
||||||
================================
|
|
||||||
|
|
||||||
1. Introduction
|
|
||||||
2. Preparation
|
|
||||||
3. Customization
|
|
||||||
4. Files
|
|
||||||
5. Modules
|
|
||||||
6. Separated build and test machines
|
|
||||||
7. Troubleshooting
|
|
||||||
Appendix A: sample script: gather_on_build.sh
|
|
||||||
Appendix B: sample script: gather_on_test.sh
|
|
||||||
|
|
||||||
|
|
||||||
1. Introduction
|
|
||||||
===============
|
|
||||||
|
|
||||||
gcov profiling kernel support enables the use of GCC's coverage testing
|
|
||||||
tool gcov [1] with the Linux kernel. Coverage data of a running kernel
|
|
||||||
is exported in gcov-compatible format via the "gcov" debugfs directory.
|
|
||||||
To get coverage data for a specific file, change to the kernel build
|
|
||||||
directory and use gcov with the -o option as follows (requires root):
|
|
||||||
|
|
||||||
# cd /tmp/linux-out
|
|
||||||
# gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
|
|
||||||
|
|
||||||
This will create source code files annotated with execution counts
|
|
||||||
in the current directory. In addition, graphical gcov front-ends such
|
|
||||||
as lcov [2] can be used to automate the process of collecting data
|
|
||||||
for the entire kernel and provide coverage overviews in HTML format.
|
|
||||||
|
|
||||||
Possible uses:
|
|
||||||
|
|
||||||
* debugging (has this line been reached at all?)
|
|
||||||
* test improvement (how do I change my test to cover these lines?)
|
|
||||||
* minimizing kernel configurations (do I need this option if the
|
|
||||||
associated code is never run?)
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
[1] http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
|
|
||||||
[2] http://ltp.sourceforge.net/coverage/lcov.php
|
|
||||||
|
|
||||||
|
|
||||||
2. Preparation
|
|
||||||
==============
|
|
||||||
|
|
||||||
Configure the kernel with:
|
|
||||||
|
|
||||||
CONFIG_DEBUG_FS=y
|
|
||||||
CONFIG_GCOV_KERNEL=y
|
|
||||||
|
|
||||||
select the gcc's gcov format, default is autodetect based on gcc version:
|
|
||||||
|
|
||||||
CONFIG_GCOV_FORMAT_AUTODETECT=y
|
|
||||||
|
|
||||||
and to get coverage data for the entire kernel:
|
|
||||||
|
|
||||||
CONFIG_GCOV_PROFILE_ALL=y
|
|
||||||
|
|
||||||
Note that kernels compiled with profiling flags will be significantly
|
|
||||||
larger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
|
|
||||||
on all architectures.
|
|
||||||
|
|
||||||
Profiling data will only become accessible once debugfs has been
|
|
||||||
mounted:
|
|
||||||
|
|
||||||
mount -t debugfs none /sys/kernel/debug
|
|
||||||
|
|
||||||
|
|
||||||
3. Customization
|
|
||||||
================
|
|
||||||
|
|
||||||
To enable profiling for specific files or directories, add a line
|
|
||||||
similar to the following to the respective kernel Makefile:
|
|
||||||
|
|
||||||
For a single file (e.g. main.o):
|
|
||||||
GCOV_PROFILE_main.o := y
|
|
||||||
|
|
||||||
For all files in one directory:
|
|
||||||
GCOV_PROFILE := y
|
|
||||||
|
|
||||||
To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
|
|
||||||
is specified, use:
|
|
||||||
|
|
||||||
GCOV_PROFILE_main.o := n
|
|
||||||
and:
|
|
||||||
GCOV_PROFILE := n
|
|
||||||
|
|
||||||
Only files which are linked to the main kernel image or are compiled as
|
|
||||||
kernel modules are supported by this mechanism.
|
|
||||||
|
|
||||||
|
|
||||||
4. Files
|
|
||||||
========
|
|
||||||
|
|
||||||
The gcov kernel support creates the following files in debugfs:
|
|
||||||
|
|
||||||
/sys/kernel/debug/gcov
|
|
||||||
Parent directory for all gcov-related files.
|
|
||||||
|
|
||||||
/sys/kernel/debug/gcov/reset
|
|
||||||
Global reset file: resets all coverage data to zero when
|
|
||||||
written to.
|
|
||||||
|
|
||||||
/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda
|
|
||||||
The actual gcov data file as understood by the gcov
|
|
||||||
tool. Resets file coverage data to zero when written to.
|
|
||||||
|
|
||||||
/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno
|
|
||||||
Symbolic link to a static data file required by the gcov
|
|
||||||
tool. This file is generated by gcc when compiling with
|
|
||||||
option -ftest-coverage.
|
|
||||||
|
|
||||||
|
|
||||||
5. Modules
|
|
||||||
==========
|
|
||||||
|
|
||||||
Kernel modules may contain cleanup code which is only run during
|
|
||||||
module unload time. The gcov mechanism provides a means to collect
|
|
||||||
coverage data for such code by keeping a copy of the data associated
|
|
||||||
with the unloaded module. This data remains available through debugfs.
|
|
||||||
Once the module is loaded again, the associated coverage counters are
|
|
||||||
initialized with the data from its previous instantiation.
|
|
||||||
|
|
||||||
This behavior can be deactivated by specifying the gcov_persist kernel
|
|
||||||
parameter:
|
|
||||||
|
|
||||||
gcov_persist=0
|
|
||||||
|
|
||||||
At run-time, a user can also choose to discard data for an unloaded
|
|
||||||
module by writing to its data file or the global reset file.
|
|
||||||
|
|
||||||
|
|
||||||
6. Separated build and test machines
|
|
||||||
====================================
|
|
||||||
|
|
||||||
The gcov kernel profiling infrastructure is designed to work out-of-the
|
|
||||||
box for setups where kernels are built and run on the same machine. In
|
|
||||||
cases where the kernel runs on a separate machine, special preparations
|
|
||||||
must be made, depending on where the gcov tool is used:
|
|
||||||
|
|
||||||
a) gcov is run on the TEST machine
|
|
||||||
|
|
||||||
The gcov tool version on the test machine must be compatible with the
|
|
||||||
gcc version used for kernel build. Also the following files need to be
|
|
||||||
copied from build to test machine:
|
|
||||||
|
|
||||||
from the source tree:
|
|
||||||
- all C source files + headers
|
|
||||||
|
|
||||||
from the build tree:
|
|
||||||
- all C source files + headers
|
|
||||||
- all .gcda and .gcno files
|
|
||||||
- all links to directories
|
|
||||||
|
|
||||||
It is important to note that these files need to be placed into the
|
|
||||||
exact same file system location on the test machine as on the build
|
|
||||||
machine. If any of the path components is symbolic link, the actual
|
|
||||||
directory needs to be used instead (due to make's CURDIR handling).
|
|
||||||
|
|
||||||
b) gcov is run on the BUILD machine
|
|
||||||
|
|
||||||
The following files need to be copied after each test case from test
|
|
||||||
to build machine:
|
|
||||||
|
|
||||||
from the gcov directory in sysfs:
|
|
||||||
- all .gcda files
|
|
||||||
- all links to .gcno files
|
|
||||||
|
|
||||||
These files can be copied to any location on the build machine. gcov
|
|
||||||
must then be called with the -o option pointing to that directory.
|
|
||||||
|
|
||||||
Example directory setup on the build machine:
|
|
||||||
|
|
||||||
/tmp/linux: kernel source tree
|
|
||||||
/tmp/out: kernel build directory as specified by make O=
|
|
||||||
/tmp/coverage: location of the files copied from the test machine
|
|
||||||
|
|
||||||
[user@build] cd /tmp/out
|
|
||||||
[user@build] gcov -o /tmp/coverage/tmp/out/init main.c
|
|
||||||
|
|
||||||
|
|
||||||
7. Troubleshooting
|
|
||||||
==================
|
|
||||||
|
|
||||||
Problem: Compilation aborts during linker step.
|
|
||||||
Cause: Profiling flags are specified for source files which are not
|
|
||||||
linked to the main kernel or which are linked by a custom
|
|
||||||
linker procedure.
|
|
||||||
Solution: Exclude affected source files from profiling by specifying
|
|
||||||
GCOV_PROFILE := n or GCOV_PROFILE_basename.o := n in the
|
|
||||||
corresponding Makefile.
|
|
||||||
|
|
||||||
Problem: Files copied from sysfs appear empty or incomplete.
|
|
||||||
Cause: Due to the way seq_file works, some tools such as cp or tar
|
|
||||||
may not correctly copy files from sysfs.
|
|
||||||
Solution: Use 'cat' to read .gcda files and 'cp -d' to copy links.
|
|
||||||
Alternatively use the mechanism shown in Appendix B.
|
|
||||||
|
|
||||||
|
|
||||||
Appendix A: gather_on_build.sh
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Sample script to gather coverage meta files on the build machine
|
|
||||||
(see 6a):
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
KSRC=$1
|
|
||||||
KOBJ=$2
|
|
||||||
DEST=$3
|
|
||||||
|
|
||||||
if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
|
|
||||||
echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
|
||||||
KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
|
||||||
|
|
||||||
find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
|
|
||||||
-perm /u+r,g+r | tar cfz $DEST -P -T -
|
|
||||||
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
echo "$DEST successfully created, copy to test system and unpack with:"
|
|
||||||
echo " tar xfz $DEST -P"
|
|
||||||
else
|
|
||||||
echo "Could not create file $DEST"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
Appendix B: gather_on_test.sh
|
|
||||||
=============================
|
|
||||||
|
|
||||||
Sample script to gather coverage data files on the test machine
|
|
||||||
(see 6b):
|
|
||||||
|
|
||||||
#!/bin/bash -e
|
|
||||||
|
|
||||||
DEST=$1
|
|
||||||
GCDA=/sys/kernel/debug/gcov
|
|
||||||
|
|
||||||
if [ -z "$DEST" ] ; then
|
|
||||||
echo "Usage: $0 <output.tar.gz>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TEMPDIR=$(mktemp -d)
|
|
||||||
echo Collecting data..
|
|
||||||
find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
|
|
||||||
find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
|
|
||||||
find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
|
|
||||||
tar czf $DEST -C $TEMPDIR sys
|
|
||||||
rm -rf $TEMPDIR
|
|
||||||
|
|
||||||
echo "$DEST successfully created, copy to build system and unpack with:"
|
|
||||||
echo " tar xfz $DEST"
|
|
5
Documentation/gpu/conf.py
Normal file
5
Documentation/gpu/conf.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8; mode: python -*-
|
||||||
|
|
||||||
|
project = "Linux GPU Driver Developer's Guide"
|
||||||
|
|
||||||
|
tags.add("subproject")
|
@@ -12,3 +12,10 @@ Linux GPU Driver Developer's Guide
|
|||||||
drm-uapi
|
drm-uapi
|
||||||
i915
|
i915
|
||||||
vga-switcheroo
|
vga-switcheroo
|
||||||
|
|
||||||
|
.. only:: subproject
|
||||||
|
|
||||||
|
Indices
|
||||||
|
=======
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
@@ -1,75 +0,0 @@
|
|||||||
HSI - High-speed Synchronous Serial Interface
|
|
||||||
|
|
||||||
1. Introduction
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
High Speed Syncronous Interface (HSI) is a fullduplex, low latency protocol,
|
|
||||||
that is optimized for die-level interconnect between an Application Processor
|
|
||||||
and a Baseband chipset. It has been specified by the MIPI alliance in 2003 and
|
|
||||||
implemented by multiple vendors since then.
|
|
||||||
|
|
||||||
The HSI interface supports full duplex communication over multiple channels
|
|
||||||
(typically 8) and is capable of reaching speeds up to 200 Mbit/s.
|
|
||||||
|
|
||||||
The serial protocol uses two signals, DATA and FLAG as combined data and clock
|
|
||||||
signals and an additional READY signal for flow control. An additional WAKE
|
|
||||||
signal can be used to wakeup the chips from standby modes. The signals are
|
|
||||||
commonly prefixed by AC for signals going from the application die to the
|
|
||||||
cellular die and CA for signals going the other way around.
|
|
||||||
|
|
||||||
+------------+ +---------------+
|
|
||||||
| Cellular | | Application |
|
|
||||||
| Die | | Die |
|
|
||||||
| | - - - - - - CAWAKE - - - - - - >| |
|
|
||||||
| T|------------ CADATA ------------>|R |
|
|
||||||
| X|------------ CAFLAG ------------>|X |
|
|
||||||
| |<----------- ACREADY ------------| |
|
|
||||||
| | | |
|
|
||||||
| | | |
|
|
||||||
| |< - - - - - ACWAKE - - - - - - -| |
|
|
||||||
| R|<----------- ACDATA -------------|T |
|
|
||||||
| X|<----------- ACFLAG -------------|X |
|
|
||||||
| |------------ CAREADY ----------->| |
|
|
||||||
| | | |
|
|
||||||
| | | |
|
|
||||||
+------------+ +---------------+
|
|
||||||
|
|
||||||
2. HSI Subsystem in Linux
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
In the Linux kernel the hsi subsystem is supposed to be used for HSI devices.
|
|
||||||
The hsi subsystem contains drivers for hsi controllers including support for
|
|
||||||
multi-port controllers and provides a generic API for using the HSI ports.
|
|
||||||
|
|
||||||
It also contains HSI client drivers, which make use of the generic API to
|
|
||||||
implement a protocol used on the HSI interface. These client drivers can
|
|
||||||
use an arbitrary number of channels.
|
|
||||||
|
|
||||||
3. hsi-char Device
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Each port automatically registers a generic client driver called hsi_char,
|
|
||||||
which provides a charecter device for userspace representing the HSI port.
|
|
||||||
It can be used to communicate via HSI from userspace. Userspace may
|
|
||||||
configure the hsi_char device using the following ioctl commands:
|
|
||||||
|
|
||||||
* HSC_RESET:
|
|
||||||
- flush the HSI port
|
|
||||||
|
|
||||||
* HSC_SET_PM
|
|
||||||
- enable or disable the client.
|
|
||||||
|
|
||||||
* HSC_SEND_BREAK
|
|
||||||
- send break
|
|
||||||
|
|
||||||
* HSC_SET_RX
|
|
||||||
- set RX configuration
|
|
||||||
|
|
||||||
* HSC_GET_RX
|
|
||||||
- get RX configuration
|
|
||||||
|
|
||||||
* HSC_SET_TX
|
|
||||||
- set TX configuration
|
|
||||||
|
|
||||||
* HSC_GET_TX
|
|
||||||
- get TX configuration
|
|
@@ -6,22 +6,18 @@
|
|||||||
Welcome to The Linux Kernel's documentation!
|
Welcome to The Linux Kernel's documentation!
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
Nothing for you to see here *yet*. Please move along.
|
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
kernel-documentation
|
kernel-documentation
|
||||||
media/media_uapi
|
dev-tools/tools
|
||||||
media/media_kapi
|
driver-api/index
|
||||||
media/dvb-drivers/index
|
media/index
|
||||||
media/v4l-drivers/index
|
|
||||||
gpu/index
|
gpu/index
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`search`
|
|
||||||
|
@@ -34,15 +34,18 @@ will need to add a a 32-bit compat layer:
|
|||||||
64-bit platforms do. So we always need padding to the natural size to get
|
64-bit platforms do. So we always need padding to the natural size to get
|
||||||
this right.
|
this right.
|
||||||
|
|
||||||
* Pad the entire struct to a multiple of 64-bits - the structure size will
|
* Pad the entire struct to a multiple of 64-bits if the structure contains
|
||||||
otherwise differ on 32-bit versus 64-bit. Having a different structure size
|
64-bit types - the structure size will otherwise differ on 32-bit versus
|
||||||
hurts when passing arrays of structures to the kernel, or if the kernel
|
64-bit. Having a different structure size hurts when passing arrays of
|
||||||
checks the structure size, which e.g. the drm core does.
|
structures to the kernel, or if the kernel checks the structure size, which
|
||||||
|
e.g. the drm core does.
|
||||||
|
|
||||||
* Pointers are __u64, cast from/to a uintprt_t on the userspace side and
|
* Pointers are __u64, cast from/to a uintprt_t on the userspace side and
|
||||||
from/to a void __user * in the kernel. Try really hard not to delay this
|
from/to a void __user * in the kernel. Try really hard not to delay this
|
||||||
conversion or worse, fiddle the raw __u64 through your code since that
|
conversion or worse, fiddle the raw __u64 through your code since that
|
||||||
diminishes the checking tools like sparse can provide.
|
diminishes the checking tools like sparse can provide. The macro
|
||||||
|
u64_to_user_ptr can be used in the kernel to avoid warnings about integers
|
||||||
|
and pointres of different sizes.
|
||||||
|
|
||||||
|
|
||||||
Basics
|
Basics
|
||||||
|
@@ -1,171 +0,0 @@
|
|||||||
KernelAddressSanitizer (KASAN)
|
|
||||||
==============================
|
|
||||||
|
|
||||||
0. Overview
|
|
||||||
===========
|
|
||||||
|
|
||||||
KernelAddressSANitizer (KASAN) is a dynamic memory error detector. It provides
|
|
||||||
a fast and comprehensive solution for finding use-after-free and out-of-bounds
|
|
||||||
bugs.
|
|
||||||
|
|
||||||
KASAN uses compile-time instrumentation for checking every memory access,
|
|
||||||
therefore you will need a GCC version 4.9.2 or later. GCC 5.0 or later is
|
|
||||||
required for detection of out-of-bounds accesses to stack or global variables.
|
|
||||||
|
|
||||||
Currently KASAN is supported only for x86_64 architecture.
|
|
||||||
|
|
||||||
1. Usage
|
|
||||||
========
|
|
||||||
|
|
||||||
To enable KASAN configure kernel with:
|
|
||||||
|
|
||||||
CONFIG_KASAN = y
|
|
||||||
|
|
||||||
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline and
|
|
||||||
inline are compiler instrumentation types. The former produces smaller binary
|
|
||||||
the latter is 1.1 - 2 times faster. Inline instrumentation requires a GCC
|
|
||||||
version 5.0 or later.
|
|
||||||
|
|
||||||
KASAN works with both SLUB and SLAB memory allocators.
|
|
||||||
For better bug detection and nicer reporting, enable CONFIG_STACKTRACE.
|
|
||||||
|
|
||||||
To disable instrumentation for specific files or directories, add a line
|
|
||||||
similar to the following to the respective kernel Makefile:
|
|
||||||
|
|
||||||
For a single file (e.g. main.o):
|
|
||||||
KASAN_SANITIZE_main.o := n
|
|
||||||
|
|
||||||
For all files in one directory:
|
|
||||||
KASAN_SANITIZE := n
|
|
||||||
|
|
||||||
1.1 Error reports
|
|
||||||
=================
|
|
||||||
|
|
||||||
A typical out of bounds access report looks like this:
|
|
||||||
|
|
||||||
==================================================================
|
|
||||||
BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
|
|
||||||
Write of size 1 by task modprobe/1689
|
|
||||||
=============================================================================
|
|
||||||
BUG kmalloc-128 (Not tainted): kasan error
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Disabling lock debugging due to kernel taint
|
|
||||||
INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
|
|
||||||
__slab_alloc+0x4b4/0x4f0
|
|
||||||
kmem_cache_alloc_trace+0x10b/0x190
|
|
||||||
kmalloc_oob_right+0x3d/0x75 [test_kasan]
|
|
||||||
init_module+0x9/0x47 [test_kasan]
|
|
||||||
do_one_initcall+0x99/0x200
|
|
||||||
load_module+0x2cb3/0x3b20
|
|
||||||
SyS_finit_module+0x76/0x80
|
|
||||||
system_call_fastpath+0x12/0x17
|
|
||||||
INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
|
|
||||||
INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
|
|
||||||
|
|
||||||
Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
|
|
||||||
Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
||||||
Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
|
|
||||||
Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........
|
|
||||||
Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
|
|
||||||
CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98
|
|
||||||
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
|
|
||||||
ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
|
|
||||||
ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
|
|
||||||
ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
|
|
||||||
Call Trace:
|
|
||||||
[<ffffffff81cc68ae>] dump_stack+0x46/0x58
|
|
||||||
[<ffffffff811fd848>] print_trailer+0xf8/0x160
|
|
||||||
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
|
||||||
[<ffffffff811ff0f5>] object_err+0x35/0x40
|
|
||||||
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
|
||||||
[<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
|
|
||||||
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
|
||||||
[<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
|
|
||||||
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
|
||||||
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
|
||||||
[<ffffffff8120a995>] __asan_store1+0x75/0xb0
|
|
||||||
[<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
|
|
||||||
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
|
||||||
[<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
|
|
||||||
[<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
|
|
||||||
[<ffffffff810002d9>] do_one_initcall+0x99/0x200
|
|
||||||
[<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
|
|
||||||
[<ffffffff81114f63>] load_module+0x2cb3/0x3b20
|
|
||||||
[<ffffffff8110fd70>] ? m_show+0x240/0x240
|
|
||||||
[<ffffffff81115f06>] SyS_finit_module+0x76/0x80
|
|
||||||
[<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
|
|
||||||
Memory state around the buggy address:
|
|
||||||
ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
||||||
ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
|
|
||||||
ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
||||||
ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
||||||
ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
|
|
||||||
>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
|
|
||||||
^
|
|
||||||
ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
||||||
ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
||||||
ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
|
|
||||||
ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
|
||||||
ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
|
||||||
==================================================================
|
|
||||||
|
|
||||||
The header of the report discribe what kind of bug happened and what kind of
|
|
||||||
access caused it. It's followed by the description of the accessed slub object
|
|
||||||
(see 'SLUB Debug output' section in Documentation/vm/slub.txt for details) and
|
|
||||||
the description of the accessed memory page.
|
|
||||||
|
|
||||||
In the last section the report shows memory state around the accessed address.
|
|
||||||
Reading this part requires some understanding of how KASAN works.
|
|
||||||
|
|
||||||
The state of each 8 aligned bytes of memory is encoded in one shadow byte.
|
|
||||||
Those 8 bytes can be accessible, partially accessible, freed or be a redzone.
|
|
||||||
We use the following encoding for each shadow byte: 0 means that all 8 bytes
|
|
||||||
of the corresponding memory region are accessible; number N (1 <= N <= 7) means
|
|
||||||
that the first N bytes are accessible, and other (8 - N) bytes are not;
|
|
||||||
any negative value indicates that the entire 8-byte word is inaccessible.
|
|
||||||
We use different negative values to distinguish between different kinds of
|
|
||||||
inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
|
|
||||||
|
|
||||||
In the report above the arrows point to the shadow byte 03, which means that
|
|
||||||
the accessed address is partially accessible.
|
|
||||||
|
|
||||||
|
|
||||||
2. Implementation details
|
|
||||||
=========================
|
|
||||||
|
|
||||||
From a high level, our approach to memory error detection is similar to that
|
|
||||||
of kmemcheck: use shadow memory to record whether each byte of memory is safe
|
|
||||||
to access, and use compile-time instrumentation to check shadow memory on each
|
|
||||||
memory access.
|
|
||||||
|
|
||||||
AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
|
|
||||||
(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
|
|
||||||
offset to translate a memory address to its corresponding shadow address.
|
|
||||||
|
|
||||||
Here is the function which translates an address to its corresponding shadow
|
|
||||||
address:
|
|
||||||
|
|
||||||
static inline void *kasan_mem_to_shadow(const void *addr)
|
|
||||||
{
|
|
||||||
return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
|
|
||||||
+ KASAN_SHADOW_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
where KASAN_SHADOW_SCALE_SHIFT = 3.
|
|
||||||
|
|
||||||
Compile-time instrumentation used for checking memory accesses. Compiler inserts
|
|
||||||
function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
|
|
||||||
access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
|
|
||||||
valid or not by checking corresponding shadow memory.
|
|
||||||
|
|
||||||
GCC 5.0 has possibility to perform inline instrumentation. Instead of making
|
|
||||||
function calls GCC directly inserts the code to check the shadow memory.
|
|
||||||
This option significantly enlarges kernel but it gives x1.1-x2 performance
|
|
||||||
boost over outline instrumented kernel.
|
|
@@ -274,7 +274,44 @@ menuconfig:
|
|||||||
|
|
||||||
This is similar to the simple config entry above, but it also gives a
|
This is similar to the simple config entry above, but it also gives a
|
||||||
hint to front ends, that all suboptions should be displayed as a
|
hint to front ends, that all suboptions should be displayed as a
|
||||||
separate list of options.
|
separate list of options. To make sure all the suboptions will really
|
||||||
|
show up under the menuconfig entry and not outside of it, every item
|
||||||
|
from the <config options> list must depend on the menuconfig symbol.
|
||||||
|
In practice, this is achieved by using one of the next two constructs:
|
||||||
|
|
||||||
|
(1):
|
||||||
|
menuconfig M
|
||||||
|
if M
|
||||||
|
config C1
|
||||||
|
config C2
|
||||||
|
endif
|
||||||
|
|
||||||
|
(2):
|
||||||
|
menuconfig M
|
||||||
|
config C1
|
||||||
|
depends on M
|
||||||
|
config C2
|
||||||
|
depends on M
|
||||||
|
|
||||||
|
In the following examples (3) and (4), C1 and C2 still have the M
|
||||||
|
dependency, but will not appear under menuconfig M anymore, because
|
||||||
|
of C0, which doesn't depend on M:
|
||||||
|
|
||||||
|
(3):
|
||||||
|
menuconfig M
|
||||||
|
config C0
|
||||||
|
if M
|
||||||
|
config C1
|
||||||
|
config C2
|
||||||
|
endif
|
||||||
|
|
||||||
|
(4):
|
||||||
|
menuconfig M
|
||||||
|
config C0
|
||||||
|
config C1
|
||||||
|
depends on M
|
||||||
|
config C2
|
||||||
|
depends on M
|
||||||
|
|
||||||
choices:
|
choices:
|
||||||
|
|
||||||
|
@@ -107,6 +107,35 @@ Here are some specific guidelines for the kernel documentation:
|
|||||||
the order as encountered."), having the higher levels the same overall makes
|
the order as encountered."), having the higher levels the same overall makes
|
||||||
it easier to follow the documents.
|
it easier to follow the documents.
|
||||||
|
|
||||||
|
|
||||||
|
the C domain
|
||||||
|
------------
|
||||||
|
|
||||||
|
The `Sphinx C Domain`_ (name c) is suited for documentation of C API. E.g. a
|
||||||
|
function prototype:
|
||||||
|
|
||||||
|
.. code-block:: rst
|
||||||
|
|
||||||
|
.. c:function:: int ioctl( int fd, int request )
|
||||||
|
|
||||||
|
The C domain of the kernel-doc has some additional features. E.g. you can
|
||||||
|
*rename* the reference name of a function with a common name like ``open`` or
|
||||||
|
``ioctl``:
|
||||||
|
|
||||||
|
.. code-block:: rst
|
||||||
|
|
||||||
|
.. c:function:: int ioctl( int fd, int request )
|
||||||
|
:name: VIDIOC_LOG_STATUS
|
||||||
|
|
||||||
|
The func-name (e.g. ioctl) remains in the output but the ref-name changed from
|
||||||
|
``ioctl`` to ``VIDIOC_LOG_STATUS``. The index entry for this function is also
|
||||||
|
changed to ``VIDIOC_LOG_STATUS`` and the function can now referenced by:
|
||||||
|
|
||||||
|
.. code-block:: rst
|
||||||
|
|
||||||
|
:c:func:`VIDIOC_LOG_STATUS`
|
||||||
|
|
||||||
|
|
||||||
list tables
|
list tables
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@@ -1695,7 +1695,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||||||
|
|
||||||
intel_idle.max_cstate= [KNL,HW,ACPI,X86]
|
intel_idle.max_cstate= [KNL,HW,ACPI,X86]
|
||||||
0 disables intel_idle and fall back on acpi_idle.
|
0 disables intel_idle and fall back on acpi_idle.
|
||||||
1 to 6 specify maximum depth of C-state.
|
1 to 9 specify maximum depth of C-state.
|
||||||
|
|
||||||
intel_pstate= [X86]
|
intel_pstate= [X86]
|
||||||
disable
|
disable
|
||||||
@@ -2168,10 +2168,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||||||
than or equal to this physical address is ignored.
|
than or equal to this physical address is ignored.
|
||||||
|
|
||||||
maxcpus= [SMP] Maximum number of processors that an SMP kernel
|
maxcpus= [SMP] Maximum number of processors that an SMP kernel
|
||||||
should make use of. maxcpus=n : n >= 0 limits the
|
will bring up during bootup. maxcpus=n : n >= 0 limits
|
||||||
kernel to using 'n' processors. n=0 is a special case,
|
the kernel to bring up 'n' processors. Surely after
|
||||||
it is equivalent to "nosmp", which also disables
|
bootup you can bring up the other plugged cpu by executing
|
||||||
the IO APIC.
|
"echo 1 > /sys/devices/system/cpu/cpuX/online". So maxcpus
|
||||||
|
only takes effect during system bootup.
|
||||||
|
While n=0 is a special case, it is equivalent to "nosmp",
|
||||||
|
which also disables the IO APIC.
|
||||||
|
|
||||||
max_loop= [LOOP] The number of loop block devices that get
|
max_loop= [LOOP] The number of loop block devices that get
|
||||||
(loop.max_loop) unconditionally pre-created at init time. The default
|
(loop.max_loop) unconditionally pre-created at init time. The default
|
||||||
@@ -2578,8 +2581,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||||||
|
|
||||||
nodelayacct [KNL] Disable per-task delay accounting
|
nodelayacct [KNL] Disable per-task delay accounting
|
||||||
|
|
||||||
nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects.
|
|
||||||
|
|
||||||
nodsp [SH] Disable hardware DSP at boot time.
|
nodsp [SH] Disable hardware DSP at boot time.
|
||||||
|
|
||||||
noefi Disable EFI runtime services support.
|
noefi Disable EFI runtime services support.
|
||||||
@@ -2780,9 +2781,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||||||
|
|
||||||
nr_cpus= [SMP] Maximum number of processors that an SMP kernel
|
nr_cpus= [SMP] Maximum number of processors that an SMP kernel
|
||||||
could support. nr_cpus=n : n >= 1 limits the kernel to
|
could support. nr_cpus=n : n >= 1 limits the kernel to
|
||||||
supporting 'n' processors. Later in runtime you can not
|
support 'n' processors. It could be larger than the
|
||||||
use hotplug cpu feature to put more cpu back to online.
|
number of already plugged CPU during bootup, later in
|
||||||
just like you compile the kernel NR_CPUS=n
|
runtime you can physically add extra cpu until it reaches
|
||||||
|
n. So during boot up some boot time memory for per-cpu
|
||||||
|
variables need be pre-allocated for later physical cpu
|
||||||
|
hot plugging.
|
||||||
|
|
||||||
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
|
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
|
||||||
|
|
||||||
|
@@ -1,754 +0,0 @@
|
|||||||
GETTING STARTED WITH KMEMCHECK
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Vegard Nossum <vegardno@ifi.uio.no>
|
|
||||||
|
|
||||||
|
|
||||||
Contents
|
|
||||||
========
|
|
||||||
0. Introduction
|
|
||||||
1. Downloading
|
|
||||||
2. Configuring and compiling
|
|
||||||
3. How to use
|
|
||||||
3.1. Booting
|
|
||||||
3.2. Run-time enable/disable
|
|
||||||
3.3. Debugging
|
|
||||||
3.4. Annotating false positives
|
|
||||||
4. Reporting errors
|
|
||||||
5. Technical description
|
|
||||||
|
|
||||||
|
|
||||||
0. Introduction
|
|
||||||
===============
|
|
||||||
|
|
||||||
kmemcheck is a debugging feature for the Linux Kernel. More specifically, it
|
|
||||||
is a dynamic checker that detects and warns about some uses of uninitialized
|
|
||||||
memory.
|
|
||||||
|
|
||||||
Userspace programmers might be familiar with Valgrind's memcheck. The main
|
|
||||||
difference between memcheck and kmemcheck is that memcheck works for userspace
|
|
||||||
programs only, and kmemcheck works for the kernel only. The implementations
|
|
||||||
are of course vastly different. Because of this, kmemcheck is not as accurate
|
|
||||||
as memcheck, but it turns out to be good enough in practice to discover real
|
|
||||||
programmer errors that the compiler is not able to find through static
|
|
||||||
analysis.
|
|
||||||
|
|
||||||
Enabling kmemcheck on a kernel will probably slow it down to the extent that
|
|
||||||
the machine will not be usable for normal workloads such as e.g. an
|
|
||||||
interactive desktop. kmemcheck will also cause the kernel to use about twice
|
|
||||||
as much memory as normal. For this reason, kmemcheck is strictly a debugging
|
|
||||||
feature.
|
|
||||||
|
|
||||||
|
|
||||||
1. Downloading
|
|
||||||
==============
|
|
||||||
|
|
||||||
As of version 2.6.31-rc1, kmemcheck is included in the mainline kernel.
|
|
||||||
|
|
||||||
|
|
||||||
2. Configuring and compiling
|
|
||||||
============================
|
|
||||||
|
|
||||||
kmemcheck only works for the x86 (both 32- and 64-bit) platform. A number of
|
|
||||||
configuration variables must have specific settings in order for the kmemcheck
|
|
||||||
menu to even appear in "menuconfig". These are:
|
|
||||||
|
|
||||||
o CONFIG_CC_OPTIMIZE_FOR_SIZE=n
|
|
||||||
|
|
||||||
This option is located under "General setup" / "Optimize for size".
|
|
||||||
|
|
||||||
Without this, gcc will use certain optimizations that usually lead to
|
|
||||||
false positive warnings from kmemcheck. An example of this is a 16-bit
|
|
||||||
field in a struct, where gcc may load 32 bits, then discard the upper
|
|
||||||
16 bits. kmemcheck sees only the 32-bit load, and may trigger a
|
|
||||||
warning for the upper 16 bits (if they're uninitialized).
|
|
||||||
|
|
||||||
o CONFIG_SLAB=y or CONFIG_SLUB=y
|
|
||||||
|
|
||||||
This option is located under "General setup" / "Choose SLAB
|
|
||||||
allocator".
|
|
||||||
|
|
||||||
o CONFIG_FUNCTION_TRACER=n
|
|
||||||
|
|
||||||
This option is located under "Kernel hacking" / "Tracers" / "Kernel
|
|
||||||
Function Tracer"
|
|
||||||
|
|
||||||
When function tracing is compiled in, gcc emits a call to another
|
|
||||||
function at the beginning of every function. This means that when the
|
|
||||||
page fault handler is called, the ftrace framework will be called
|
|
||||||
before kmemcheck has had a chance to handle the fault. If ftrace then
|
|
||||||
modifies memory that was tracked by kmemcheck, the result is an
|
|
||||||
endless recursive page fault.
|
|
||||||
|
|
||||||
o CONFIG_DEBUG_PAGEALLOC=n
|
|
||||||
|
|
||||||
This option is located under "Kernel hacking" / "Memory Debugging"
|
|
||||||
/ "Debug page memory allocations".
|
|
||||||
|
|
||||||
In addition, I highly recommend turning on CONFIG_DEBUG_INFO=y. This is also
|
|
||||||
located under "Kernel hacking". With this, you will be able to get line number
|
|
||||||
information from the kmemcheck warnings, which is extremely valuable in
|
|
||||||
debugging a problem. This option is not mandatory, however, because it slows
|
|
||||||
down the compilation process and produces a much bigger kernel image.
|
|
||||||
|
|
||||||
Now the kmemcheck menu should be visible (under "Kernel hacking" / "Memory
|
|
||||||
Debugging" / "kmemcheck: trap use of uninitialized memory"). Here follows
|
|
||||||
a description of the kmemcheck configuration variables:
|
|
||||||
|
|
||||||
o CONFIG_KMEMCHECK
|
|
||||||
|
|
||||||
This must be enabled in order to use kmemcheck at all...
|
|
||||||
|
|
||||||
o CONFIG_KMEMCHECK_[DISABLED | ENABLED | ONESHOT]_BY_DEFAULT
|
|
||||||
|
|
||||||
This option controls the status of kmemcheck at boot-time. "Enabled"
|
|
||||||
will enable kmemcheck right from the start, "disabled" will boot the
|
|
||||||
kernel as normal (but with the kmemcheck code compiled in, so it can
|
|
||||||
be enabled at run-time after the kernel has booted), and "one-shot" is
|
|
||||||
a special mode which will turn kmemcheck off automatically after
|
|
||||||
detecting the first use of uninitialized memory.
|
|
||||||
|
|
||||||
If you are using kmemcheck to actively debug a problem, then you
|
|
||||||
probably want to choose "enabled" here.
|
|
||||||
|
|
||||||
The one-shot mode is mostly useful in automated test setups because it
|
|
||||||
can prevent floods of warnings and increase the chances of the machine
|
|
||||||
surviving in case something is really wrong. In other cases, the one-
|
|
||||||
shot mode could actually be counter-productive because it would turn
|
|
||||||
itself off at the very first error -- in the case of a false positive
|
|
||||||
too -- and this would come in the way of debugging the specific
|
|
||||||
problem you were interested in.
|
|
||||||
|
|
||||||
If you would like to use your kernel as normal, but with a chance to
|
|
||||||
enable kmemcheck in case of some problem, it might be a good idea to
|
|
||||||
choose "disabled" here. When kmemcheck is disabled, most of the run-
|
|
||||||
time overhead is not incurred, and the kernel will be almost as fast
|
|
||||||
as normal.
|
|
||||||
|
|
||||||
o CONFIG_KMEMCHECK_QUEUE_SIZE
|
|
||||||
|
|
||||||
Select the maximum number of error reports to store in an internal
|
|
||||||
(fixed-size) buffer. Since errors can occur virtually anywhere and in
|
|
||||||
any context, we need a temporary storage area which is guaranteed not
|
|
||||||
to generate any other page faults when accessed. The queue will be
|
|
||||||
emptied as soon as a tasklet may be scheduled. If the queue is full,
|
|
||||||
new error reports will be lost.
|
|
||||||
|
|
||||||
The default value of 64 is probably fine. If some code produces more
|
|
||||||
than 64 errors within an irqs-off section, then the code is likely to
|
|
||||||
produce many, many more, too, and these additional reports seldom give
|
|
||||||
any more information (the first report is usually the most valuable
|
|
||||||
anyway).
|
|
||||||
|
|
||||||
This number might have to be adjusted if you are not using serial
|
|
||||||
console or similar to capture the kernel log. If you are using the
|
|
||||||
"dmesg" command to save the log, then getting a lot of kmemcheck
|
|
||||||
warnings might overflow the kernel log itself, and the earlier reports
|
|
||||||
will get lost in that way instead. Try setting this to 10 or so on
|
|
||||||
such a setup.
|
|
||||||
|
|
||||||
o CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT
|
|
||||||
|
|
||||||
Select the number of shadow bytes to save along with each entry of the
|
|
||||||
error-report queue. These bytes indicate what parts of an allocation
|
|
||||||
are initialized, uninitialized, etc. and will be displayed when an
|
|
||||||
error is detected to help the debugging of a particular problem.
|
|
||||||
|
|
||||||
The number entered here is actually the logarithm of the number of
|
|
||||||
bytes that will be saved. So if you pick for example 5 here, kmemcheck
|
|
||||||
will save 2^5 = 32 bytes.
|
|
||||||
|
|
||||||
The default value should be fine for debugging most problems. It also
|
|
||||||
fits nicely within 80 columns.
|
|
||||||
|
|
||||||
o CONFIG_KMEMCHECK_PARTIAL_OK
|
|
||||||
|
|
||||||
This option (when enabled) works around certain GCC optimizations that
|
|
||||||
produce 32-bit reads from 16-bit variables where the upper 16 bits are
|
|
||||||
thrown away afterwards.
|
|
||||||
|
|
||||||
The default value (enabled) is recommended. This may of course hide
|
|
||||||
some real errors, but disabling it would probably produce a lot of
|
|
||||||
false positives.
|
|
||||||
|
|
||||||
o CONFIG_KMEMCHECK_BITOPS_OK
|
|
||||||
|
|
||||||
This option silences warnings that would be generated for bit-field
|
|
||||||
accesses where not all the bits are initialized at the same time. This
|
|
||||||
may also hide some real bugs.
|
|
||||||
|
|
||||||
This option is probably obsolete, or it should be replaced with
|
|
||||||
the kmemcheck-/bitfield-annotations for the code in question. The
|
|
||||||
default value is therefore fine.
|
|
||||||
|
|
||||||
Now compile the kernel as usual.
|
|
||||||
|
|
||||||
|
|
||||||
3. How to use
|
|
||||||
=============
|
|
||||||
|
|
||||||
3.1. Booting
|
|
||||||
============
|
|
||||||
|
|
||||||
First some information about the command-line options. There is only one
|
|
||||||
option specific to kmemcheck, and this is called "kmemcheck". It can be used
|
|
||||||
to override the default mode as chosen by the CONFIG_KMEMCHECK_*_BY_DEFAULT
|
|
||||||
option. Its possible settings are:
|
|
||||||
|
|
||||||
o kmemcheck=0 (disabled)
|
|
||||||
o kmemcheck=1 (enabled)
|
|
||||||
o kmemcheck=2 (one-shot mode)
|
|
||||||
|
|
||||||
If SLUB debugging has been enabled in the kernel, it may take precedence over
|
|
||||||
kmemcheck in such a way that the slab caches which are under SLUB debugging
|
|
||||||
will not be tracked by kmemcheck. In order to ensure that this doesn't happen
|
|
||||||
(even though it shouldn't by default), use SLUB's boot option "slub_debug",
|
|
||||||
like this: slub_debug=-
|
|
||||||
|
|
||||||
In fact, this option may also be used for fine-grained control over SLUB vs.
|
|
||||||
kmemcheck. For example, if the command line includes "kmemcheck=1
|
|
||||||
slub_debug=,dentry", then SLUB debugging will be used only for the "dentry"
|
|
||||||
slab cache, and with kmemcheck tracking all the other caches. This is advanced
|
|
||||||
usage, however, and is not generally recommended.
|
|
||||||
|
|
||||||
|
|
||||||
3.2. Run-time enable/disable
|
|
||||||
============================
|
|
||||||
|
|
||||||
When the kernel has booted, it is possible to enable or disable kmemcheck at
|
|
||||||
run-time. WARNING: This feature is still experimental and may cause false
|
|
||||||
positive warnings to appear. Therefore, try not to use this. If you find that
|
|
||||||
it doesn't work properly (e.g. you see an unreasonable amount of warnings), I
|
|
||||||
will be happy to take bug reports.
|
|
||||||
|
|
||||||
Use the file /proc/sys/kernel/kmemcheck for this purpose, e.g.:
|
|
||||||
|
|
||||||
$ echo 0 > /proc/sys/kernel/kmemcheck # disables kmemcheck
|
|
||||||
|
|
||||||
The numbers are the same as for the kmemcheck= command-line option.
|
|
||||||
|
|
||||||
|
|
||||||
3.3. Debugging
|
|
||||||
==============
|
|
||||||
|
|
||||||
A typical report will look something like this:
|
|
||||||
|
|
||||||
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
|
||||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
|
||||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
|
||||||
^
|
|
||||||
|
|
||||||
Pid: 1856, comm: ntpdate Not tainted 2.6.29-rc5 #264 945P-A
|
|
||||||
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
|
||||||
RSP: 0018:ffff88003cdf7d98 EFLAGS: 00210002
|
|
||||||
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
|
||||||
RDX: ffff88003e5d6018 RSI: ffff88003e5d6024 RDI: ffff88003cdf7e84
|
|
||||||
RBP: ffff88003cdf7db8 R08: ffff88003e5d6000 R09: 0000000000000000
|
|
||||||
R10: 0000000000000080 R11: 0000000000000000 R12: 000000000000000e
|
|
||||||
R13: ffff88003cdf7e78 R14: ffff88003d530710 R15: ffff88003d5a98c8
|
|
||||||
FS: 0000000000000000(0000) GS:ffff880001982000(0063) knlGS:00000
|
|
||||||
CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033
|
|
||||||
CR2: ffff88003f806ea0 CR3: 000000003c036000 CR4: 00000000000006a0
|
|
||||||
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
|
||||||
DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
|
|
||||||
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
|
||||||
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
|
||||||
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
|
||||||
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
|
||||||
[<ffffffffffffffff>] 0xffffffffffffffff
|
|
||||||
|
|
||||||
The single most valuable information in this report is the RIP (or EIP on 32-
|
|
||||||
bit) value. This will help us pinpoint exactly which instruction that caused
|
|
||||||
the warning.
|
|
||||||
|
|
||||||
If your kernel was compiled with CONFIG_DEBUG_INFO=y, then all we have to do
|
|
||||||
is give this address to the addr2line program, like this:
|
|
||||||
|
|
||||||
$ addr2line -e vmlinux -i ffffffff8104ede8
|
|
||||||
arch/x86/include/asm/string_64.h:12
|
|
||||||
include/asm-generic/siginfo.h:287
|
|
||||||
kernel/signal.c:380
|
|
||||||
kernel/signal.c:410
|
|
||||||
|
|
||||||
The "-e vmlinux" tells addr2line which file to look in. IMPORTANT: This must
|
|
||||||
be the vmlinux of the kernel that produced the warning in the first place! If
|
|
||||||
not, the line number information will almost certainly be wrong.
|
|
||||||
|
|
||||||
The "-i" tells addr2line to also print the line numbers of inlined functions.
|
|
||||||
In this case, the flag was very important, because otherwise, it would only
|
|
||||||
have printed the first line, which is just a call to memcpy(), which could be
|
|
||||||
called from a thousand places in the kernel, and is therefore not very useful.
|
|
||||||
These inlined functions would not show up in the stack trace above, simply
|
|
||||||
because the kernel doesn't load the extra debugging information. This
|
|
||||||
technique can of course be used with ordinary kernel oopses as well.
|
|
||||||
|
|
||||||
In this case, it's the caller of memcpy() that is interesting, and it can be
|
|
||||||
found in include/asm-generic/siginfo.h, line 287:
|
|
||||||
|
|
||||||
281 static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
|
|
||||||
282 {
|
|
||||||
283 if (from->si_code < 0)
|
|
||||||
284 memcpy(to, from, sizeof(*to));
|
|
||||||
285 else
|
|
||||||
286 /* _sigchld is currently the largest know union member */
|
|
||||||
287 memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
|
|
||||||
288 }
|
|
||||||
|
|
||||||
Since this was a read (kmemcheck usually warns about reads only, though it can
|
|
||||||
warn about writes to unallocated or freed memory as well), it was probably the
|
|
||||||
"from" argument which contained some uninitialized bytes. Following the chain
|
|
||||||
of calls, we move upwards to see where "from" was allocated or initialized,
|
|
||||||
kernel/signal.c, line 380:
|
|
||||||
|
|
||||||
359 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
|
|
||||||
360 {
|
|
||||||
...
|
|
||||||
367 list_for_each_entry(q, &list->list, list) {
|
|
||||||
368 if (q->info.si_signo == sig) {
|
|
||||||
369 if (first)
|
|
||||||
370 goto still_pending;
|
|
||||||
371 first = q;
|
|
||||||
...
|
|
||||||
377 if (first) {
|
|
||||||
378 still_pending:
|
|
||||||
379 list_del_init(&first->list);
|
|
||||||
380 copy_siginfo(info, &first->info);
|
|
||||||
381 __sigqueue_free(first);
|
|
||||||
...
|
|
||||||
392 }
|
|
||||||
393 }
|
|
||||||
|
|
||||||
Here, it is &first->info that is being passed on to copy_siginfo(). The
|
|
||||||
variable "first" was found on a list -- passed in as the second argument to
|
|
||||||
collect_signal(). We continue our journey through the stack, to figure out
|
|
||||||
where the item on "list" was allocated or initialized. We move to line 410:
|
|
||||||
|
|
||||||
395 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
|
|
||||||
396 siginfo_t *info)
|
|
||||||
397 {
|
|
||||||
...
|
|
||||||
410 collect_signal(sig, pending, info);
|
|
||||||
...
|
|
||||||
414 }
|
|
||||||
|
|
||||||
Now we need to follow the "pending" pointer, since that is being passed on to
|
|
||||||
collect_signal() as "list". At this point, we've run out of lines from the
|
|
||||||
"addr2line" output. Not to worry, we just paste the next addresses from the
|
|
||||||
kmemcheck stack dump, i.e.:
|
|
||||||
|
|
||||||
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
|
||||||
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
|
||||||
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
|
||||||
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
|
||||||
|
|
||||||
$ addr2line -e vmlinux -i ffffffff8104f04e ffffffff81050bd8 \
|
|
||||||
ffffffff8100b87d ffffffff8100c7b5
|
|
||||||
kernel/signal.c:446
|
|
||||||
kernel/signal.c:1806
|
|
||||||
arch/x86/kernel/signal.c:805
|
|
||||||
arch/x86/kernel/signal.c:871
|
|
||||||
arch/x86/kernel/entry_64.S:694
|
|
||||||
|
|
||||||
Remember that since these addresses were found on the stack and not as the
|
|
||||||
RIP value, they actually point to the _next_ instruction (they are return
|
|
||||||
addresses). This becomes obvious when we look at the code for line 446:
|
|
||||||
|
|
||||||
422 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
|
||||||
423 {
|
|
||||||
...
|
|
||||||
431 signr = __dequeue_signal(&tsk->signal->shared_pending,
|
|
||||||
432 mask, info);
|
|
||||||
433 /*
|
|
||||||
434 * itimer signal ?
|
|
||||||
435 *
|
|
||||||
436 * itimers are process shared and we restart periodic
|
|
||||||
437 * itimers in the signal delivery path to prevent DoS
|
|
||||||
438 * attacks in the high resolution timer case. This is
|
|
||||||
439 * compliant with the old way of self restarting
|
|
||||||
440 * itimers, as the SIGALRM is a legacy signal and only
|
|
||||||
441 * queued once. Changing the restart behaviour to
|
|
||||||
442 * restart the timer in the signal dequeue path is
|
|
||||||
443 * reducing the timer noise on heavy loaded !highres
|
|
||||||
444 * systems too.
|
|
||||||
445 */
|
|
||||||
446 if (unlikely(signr == SIGALRM)) {
|
|
||||||
...
|
|
||||||
489 }
|
|
||||||
|
|
||||||
So instead of looking at 446, we should be looking at 431, which is the line
|
|
||||||
that executes just before 446. Here we see that what we are looking for is
|
|
||||||
&tsk->signal->shared_pending.
|
|
||||||
|
|
||||||
Our next task is now to figure out which function that puts items on this
|
|
||||||
"shared_pending" list. A crude, but efficient tool, is git grep:
|
|
||||||
|
|
||||||
$ git grep -n 'shared_pending' kernel/
|
|
||||||
...
|
|
||||||
kernel/signal.c:828: pending = group ? &t->signal->shared_pending : &t->pending;
|
|
||||||
kernel/signal.c:1339: pending = group ? &t->signal->shared_pending : &t->pending;
|
|
||||||
...
|
|
||||||
|
|
||||||
There were more results, but none of them were related to list operations,
|
|
||||||
and these were the only assignments. We inspect the line numbers more closely
|
|
||||||
and find that this is indeed where items are being added to the list:
|
|
||||||
|
|
||||||
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
||||||
817 int group)
|
|
||||||
818 {
|
|
||||||
...
|
|
||||||
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
|
||||||
...
|
|
||||||
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
|
||||||
852 (is_si_special(info) ||
|
|
||||||
853 info->si_code >= 0)));
|
|
||||||
854 if (q) {
|
|
||||||
855 list_add_tail(&q->list, &pending->list);
|
|
||||||
...
|
|
||||||
890 }
|
|
||||||
|
|
||||||
and:
|
|
||||||
|
|
||||||
1309 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
|
|
||||||
1310 {
|
|
||||||
....
|
|
||||||
1339 pending = group ? &t->signal->shared_pending : &t->pending;
|
|
||||||
1340 list_add_tail(&q->list, &pending->list);
|
|
||||||
....
|
|
||||||
1347 }
|
|
||||||
|
|
||||||
In the first case, the list element we are looking for, "q", is being returned
|
|
||||||
from the function __sigqueue_alloc(), which looks like an allocation function.
|
|
||||||
Let's take a look at it:
|
|
||||||
|
|
||||||
187 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
|
|
||||||
188 int override_rlimit)
|
|
||||||
189 {
|
|
||||||
190 struct sigqueue *q = NULL;
|
|
||||||
191 struct user_struct *user;
|
|
||||||
192
|
|
||||||
193 /*
|
|
||||||
194 * We won't get problems with the target's UID changing under us
|
|
||||||
195 * because changing it requires RCU be used, and if t != current, the
|
|
||||||
196 * caller must be holding the RCU readlock (by way of a spinlock) and
|
|
||||||
197 * we use RCU protection here
|
|
||||||
198 */
|
|
||||||
199 user = get_uid(__task_cred(t)->user);
|
|
||||||
200 atomic_inc(&user->sigpending);
|
|
||||||
201 if (override_rlimit ||
|
|
||||||
202 atomic_read(&user->sigpending) <=
|
|
||||||
203 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
|
|
||||||
204 q = kmem_cache_alloc(sigqueue_cachep, flags);
|
|
||||||
205 if (unlikely(q == NULL)) {
|
|
||||||
206 atomic_dec(&user->sigpending);
|
|
||||||
207 free_uid(user);
|
|
||||||
208 } else {
|
|
||||||
209 INIT_LIST_HEAD(&q->list);
|
|
||||||
210 q->flags = 0;
|
|
||||||
211 q->user = user;
|
|
||||||
212 }
|
|
||||||
213
|
|
||||||
214 return q;
|
|
||||||
215 }
|
|
||||||
|
|
||||||
We see that this function initializes q->list, q->flags, and q->user. It seems
|
|
||||||
that now is the time to look at the definition of "struct sigqueue", e.g.:
|
|
||||||
|
|
||||||
14 struct sigqueue {
|
|
||||||
15 struct list_head list;
|
|
||||||
16 int flags;
|
|
||||||
17 siginfo_t info;
|
|
||||||
18 struct user_struct *user;
|
|
||||||
19 };
|
|
||||||
|
|
||||||
And, you might remember, it was a memcpy() on &first->info that caused the
|
|
||||||
warning, so this makes perfect sense. It also seems reasonable to assume that
|
|
||||||
it is the caller of __sigqueue_alloc() that has the responsibility of filling
|
|
||||||
out (initializing) this member.
|
|
||||||
|
|
||||||
But just which fields of the struct were uninitialized? Let's look at
|
|
||||||
kmemcheck's report again:
|
|
||||||
|
|
||||||
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
|
||||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
|
||||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
|
||||||
^
|
|
||||||
|
|
||||||
These first two lines are the memory dump of the memory object itself, and the
|
|
||||||
shadow bytemap, respectively. The memory object itself is in this case
|
|
||||||
&first->info. Just beware that the start of this dump is NOT the start of the
|
|
||||||
object itself! The position of the caret (^) corresponds with the address of
|
|
||||||
the read (ffff88003e4a2024).
|
|
||||||
|
|
||||||
The shadow bytemap dump legend is as follows:
|
|
||||||
|
|
||||||
i - initialized
|
|
||||||
u - uninitialized
|
|
||||||
a - unallocated (memory has been allocated by the slab layer, but has not
|
|
||||||
yet been handed off to anybody)
|
|
||||||
f - freed (memory has been allocated by the slab layer, but has been freed
|
|
||||||
by the previous owner)
|
|
||||||
|
|
||||||
In order to figure out where (relative to the start of the object) the
|
|
||||||
uninitialized memory was located, we have to look at the disassembly. For
|
|
||||||
that, we'll need the RIP address again:
|
|
||||||
|
|
||||||
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
|
||||||
|
|
||||||
$ objdump -d --no-show-raw-insn vmlinux | grep -C 8 ffffffff8104ede8:
|
|
||||||
ffffffff8104edc8: mov %r8,0x8(%r8)
|
|
||||||
ffffffff8104edcc: test %r10d,%r10d
|
|
||||||
ffffffff8104edcf: js ffffffff8104ee88 <__dequeue_signal+0x168>
|
|
||||||
ffffffff8104edd5: mov %rax,%rdx
|
|
||||||
ffffffff8104edd8: mov $0xc,%ecx
|
|
||||||
ffffffff8104eddd: mov %r13,%rdi
|
|
||||||
ffffffff8104ede0: mov $0x30,%eax
|
|
||||||
ffffffff8104ede5: mov %rdx,%rsi
|
|
||||||
ffffffff8104ede8: rep movsl %ds:(%rsi),%es:(%rdi)
|
|
||||||
ffffffff8104edea: test $0x2,%al
|
|
||||||
ffffffff8104edec: je ffffffff8104edf0 <__dequeue_signal+0xd0>
|
|
||||||
ffffffff8104edee: movsw %ds:(%rsi),%es:(%rdi)
|
|
||||||
ffffffff8104edf0: test $0x1,%al
|
|
||||||
ffffffff8104edf2: je ffffffff8104edf5 <__dequeue_signal+0xd5>
|
|
||||||
ffffffff8104edf4: movsb %ds:(%rsi),%es:(%rdi)
|
|
||||||
ffffffff8104edf5: mov %r8,%rdi
|
|
||||||
ffffffff8104edf8: callq ffffffff8104de60 <__sigqueue_free>
|
|
||||||
|
|
||||||
As expected, it's the "rep movsl" instruction from the memcpy() that causes
|
|
||||||
the warning. We know about REP MOVSL that it uses the register RCX to count
|
|
||||||
the number of remaining iterations. By taking a look at the register dump
|
|
||||||
again (from the kmemcheck report), we can figure out how many bytes were left
|
|
||||||
to copy:
|
|
||||||
|
|
||||||
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
|
||||||
|
|
||||||
By looking at the disassembly, we also see that %ecx is being loaded with the
|
|
||||||
value $0xc just before (ffffffff8104edd8), so we are very lucky. Keep in mind
|
|
||||||
that this is the number of iterations, not bytes. And since this is a "long"
|
|
||||||
operation, we need to multiply by 4 to get the number of bytes. So this means
|
|
||||||
that the uninitialized value was encountered at 4 * (0xc - 0x9) = 12 bytes
|
|
||||||
from the start of the object.
|
|
||||||
|
|
||||||
We can now try to figure out which field of the "struct siginfo" that was not
|
|
||||||
initialized. This is the beginning of the struct:
|
|
||||||
|
|
||||||
40 typedef struct siginfo {
|
|
||||||
41 int si_signo;
|
|
||||||
42 int si_errno;
|
|
||||||
43 int si_code;
|
|
||||||
44
|
|
||||||
45 union {
|
|
||||||
..
|
|
||||||
92 } _sifields;
|
|
||||||
93 } siginfo_t;
|
|
||||||
|
|
||||||
On 64-bit, the int is 4 bytes long, so it must the union member that has
|
|
||||||
not been initialized. We can verify this using gdb:
|
|
||||||
|
|
||||||
$ gdb vmlinux
|
|
||||||
...
|
|
||||||
(gdb) p &((struct siginfo *) 0)->_sifields
|
|
||||||
$1 = (union {...} *) 0x10
|
|
||||||
|
|
||||||
Actually, it seems that the union member is located at offset 0x10 -- which
|
|
||||||
means that gcc has inserted 4 bytes of padding between the members si_code
|
|
||||||
and _sifields. We can now get a fuller picture of the memory dump:
|
|
||||||
|
|
||||||
_----------------------------=> si_code
|
|
||||||
/ _--------------------=> (padding)
|
|
||||||
| / _------------=> _sifields(._kill._pid)
|
|
||||||
| | / _----=> _sifields(._kill._uid)
|
|
||||||
| | | /
|
|
||||||
-------|-------|-------|-------|
|
|
||||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
|
||||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
|
||||||
|
|
||||||
This allows us to realize another important fact: si_code contains the value
|
|
||||||
0x80. Remember that x86 is little endian, so the first 4 bytes "80000000" are
|
|
||||||
really the number 0x00000080. With a bit of research, we find that this is
|
|
||||||
actually the constant SI_KERNEL defined in include/asm-generic/siginfo.h:
|
|
||||||
|
|
||||||
144 #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
|
||||||
|
|
||||||
This macro is used in exactly one place in the x86 kernel: In send_signal()
|
|
||||||
in kernel/signal.c:
|
|
||||||
|
|
||||||
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
||||||
817 int group)
|
|
||||||
818 {
|
|
||||||
...
|
|
||||||
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
|
||||||
...
|
|
||||||
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
|
||||||
852 (is_si_special(info) ||
|
|
||||||
853 info->si_code >= 0)));
|
|
||||||
854 if (q) {
|
|
||||||
855 list_add_tail(&q->list, &pending->list);
|
|
||||||
856 switch ((unsigned long) info) {
|
|
||||||
...
|
|
||||||
865 case (unsigned long) SEND_SIG_PRIV:
|
|
||||||
866 q->info.si_signo = sig;
|
|
||||||
867 q->info.si_errno = 0;
|
|
||||||
868 q->info.si_code = SI_KERNEL;
|
|
||||||
869 q->info.si_pid = 0;
|
|
||||||
870 q->info.si_uid = 0;
|
|
||||||
871 break;
|
|
||||||
...
|
|
||||||
890 }
|
|
||||||
|
|
||||||
Not only does this match with the .si_code member, it also matches the place
|
|
||||||
we found earlier when looking for where siginfo_t objects are enqueued on the
|
|
||||||
"shared_pending" list.
|
|
||||||
|
|
||||||
So to sum up: It seems that it is the padding introduced by the compiler
|
|
||||||
between two struct fields that is uninitialized, and this gets reported when
|
|
||||||
we do a memcpy() on the struct. This means that we have identified a false
|
|
||||||
positive warning.
|
|
||||||
|
|
||||||
Normally, kmemcheck will not report uninitialized accesses in memcpy() calls
|
|
||||||
when both the source and destination addresses are tracked. (Instead, we copy
|
|
||||||
the shadow bytemap as well). In this case, the destination address clearly
|
|
||||||
was not tracked. We can dig a little deeper into the stack trace from above:
|
|
||||||
|
|
||||||
arch/x86/kernel/signal.c:805
|
|
||||||
arch/x86/kernel/signal.c:871
|
|
||||||
arch/x86/kernel/entry_64.S:694
|
|
||||||
|
|
||||||
And we clearly see that the destination siginfo object is located on the
|
|
||||||
stack:
|
|
||||||
|
|
||||||
782 static void do_signal(struct pt_regs *regs)
|
|
||||||
783 {
|
|
||||||
784 struct k_sigaction ka;
|
|
||||||
785 siginfo_t info;
|
|
||||||
...
|
|
||||||
804 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
||||||
...
|
|
||||||
854 }
|
|
||||||
|
|
||||||
And this &info is what eventually gets passed to copy_siginfo() as the
|
|
||||||
destination argument.
|
|
||||||
|
|
||||||
Now, even though we didn't find an actual error here, the example is still a
|
|
||||||
good one, because it shows how one would go about to find out what the report
|
|
||||||
was all about.
|
|
||||||
|
|
||||||
|
|
||||||
3.4. Annotating false positives
|
|
||||||
===============================
|
|
||||||
|
|
||||||
There are a few different ways to make annotations in the source code that
|
|
||||||
will keep kmemcheck from checking and reporting certain allocations. Here
|
|
||||||
they are:
|
|
||||||
|
|
||||||
o __GFP_NOTRACK_FALSE_POSITIVE
|
|
||||||
|
|
||||||
This flag can be passed to kmalloc() or kmem_cache_alloc() (therefore
|
|
||||||
also to other functions that end up calling one of these) to indicate
|
|
||||||
that the allocation should not be tracked because it would lead to
|
|
||||||
a false positive report. This is a "big hammer" way of silencing
|
|
||||||
kmemcheck; after all, even if the false positive pertains to
|
|
||||||
particular field in a struct, for example, we will now lose the
|
|
||||||
ability to find (real) errors in other parts of the same struct.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
/* No warnings will ever trigger on accessing any part of x */
|
|
||||||
x = kmalloc(sizeof *x, GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE);
|
|
||||||
|
|
||||||
o kmemcheck_bitfield_begin(name)/kmemcheck_bitfield_end(name) and
|
|
||||||
kmemcheck_annotate_bitfield(ptr, name)
|
|
||||||
|
|
||||||
The first two of these three macros can be used inside struct
|
|
||||||
definitions to signal, respectively, the beginning and end of a
|
|
||||||
bitfield. Additionally, this will assign the bitfield a name, which
|
|
||||||
is given as an argument to the macros.
|
|
||||||
|
|
||||||
Having used these markers, one can later use
|
|
||||||
kmemcheck_annotate_bitfield() at the point of allocation, to indicate
|
|
||||||
which parts of the allocation is part of a bitfield.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
struct foo {
|
|
||||||
int x;
|
|
||||||
|
|
||||||
kmemcheck_bitfield_begin(flags);
|
|
||||||
int flag_a:1;
|
|
||||||
int flag_b:1;
|
|
||||||
kmemcheck_bitfield_end(flags);
|
|
||||||
|
|
||||||
int y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct foo *x = kmalloc(sizeof *x);
|
|
||||||
|
|
||||||
/* No warnings will trigger on accessing the bitfield of x */
|
|
||||||
kmemcheck_annotate_bitfield(x, flags);
|
|
||||||
|
|
||||||
Note that kmemcheck_annotate_bitfield() can be used even before the
|
|
||||||
return value of kmalloc() is checked -- in other words, passing NULL
|
|
||||||
as the first argument is legal (and will do nothing).
|
|
||||||
|
|
||||||
|
|
||||||
4. Reporting errors
|
|
||||||
===================
|
|
||||||
|
|
||||||
As we have seen, kmemcheck will produce false positive reports. Therefore, it
|
|
||||||
is not very wise to blindly post kmemcheck warnings to mailing lists and
|
|
||||||
maintainers. Instead, I encourage maintainers and developers to find errors
|
|
||||||
in their own code. If you get a warning, you can try to work around it, try
|
|
||||||
to figure out if it's a real error or not, or simply ignore it. Most
|
|
||||||
developers know their own code and will quickly and efficiently determine the
|
|
||||||
root cause of a kmemcheck report. This is therefore also the most efficient
|
|
||||||
way to work with kmemcheck.
|
|
||||||
|
|
||||||
That said, we (the kmemcheck maintainers) will always be on the lookout for
|
|
||||||
false positives that we can annotate and silence. So whatever you find,
|
|
||||||
please drop us a note privately! Kernel configs and steps to reproduce (if
|
|
||||||
available) are of course a great help too.
|
|
||||||
|
|
||||||
Happy hacking!
|
|
||||||
|
|
||||||
|
|
||||||
5. Technical description
|
|
||||||
========================
|
|
||||||
|
|
||||||
kmemcheck works by marking memory pages non-present. This means that whenever
|
|
||||||
somebody attempts to access the page, a page fault is generated. The page
|
|
||||||
fault handler notices that the page was in fact only hidden, and so it calls
|
|
||||||
on the kmemcheck code to make further investigations.
|
|
||||||
|
|
||||||
When the investigations are completed, kmemcheck "shows" the page by marking
|
|
||||||
it present (as it would be under normal circumstances). This way, the
|
|
||||||
interrupted code can continue as usual.
|
|
||||||
|
|
||||||
But after the instruction has been executed, we should hide the page again, so
|
|
||||||
that we can catch the next access too! Now kmemcheck makes use of a debugging
|
|
||||||
feature of the processor, namely single-stepping. When the processor has
|
|
||||||
finished the one instruction that generated the memory access, a debug
|
|
||||||
exception is raised. From here, we simply hide the page again and continue
|
|
||||||
execution, this time with the single-stepping feature turned off.
|
|
||||||
|
|
||||||
kmemcheck requires some assistance from the memory allocator in order to work.
|
|
||||||
The memory allocator needs to
|
|
||||||
|
|
||||||
1. Tell kmemcheck about newly allocated pages and pages that are about to
|
|
||||||
be freed. This allows kmemcheck to set up and tear down the shadow memory
|
|
||||||
for the pages in question. The shadow memory stores the status of each
|
|
||||||
byte in the allocation proper, e.g. whether it is initialized or
|
|
||||||
uninitialized.
|
|
||||||
|
|
||||||
2. Tell kmemcheck which parts of memory should be marked uninitialized.
|
|
||||||
There are actually a few more states, such as "not yet allocated" and
|
|
||||||
"recently freed".
|
|
||||||
|
|
||||||
If a slab cache is set up using the SLAB_NOTRACK flag, it will never return
|
|
||||||
memory that can take page faults because of kmemcheck.
|
|
||||||
|
|
||||||
If a slab cache is NOT set up using the SLAB_NOTRACK flag, callers can still
|
|
||||||
request memory with the __GFP_NOTRACK or __GFP_NOTRACK_FALSE_POSITIVE flags.
|
|
||||||
This does not prevent the page faults from occurring, however, but marks the
|
|
||||||
object in question as being initialized so that no warnings will ever be
|
|
||||||
produced for this object.
|
|
||||||
|
|
||||||
Currently, the SLAB and SLUB allocators are supported by kmemcheck.
|
|
@@ -103,6 +103,16 @@ Note that the probed function's args may be passed on the stack
|
|||||||
or in registers. The jprobe will work in either case, so long as the
|
or in registers. The jprobe will work in either case, so long as the
|
||||||
handler's prototype matches that of the probed function.
|
handler's prototype matches that of the probed function.
|
||||||
|
|
||||||
|
Note that in some architectures (e.g.: arm64 and sparc64) the stack
|
||||||
|
copy is not done, as the actual location of stacked parameters may be
|
||||||
|
outside of a reasonable MAX_STACK_SIZE value and because that location
|
||||||
|
cannot be determined by the jprobes code. In this case the jprobes
|
||||||
|
user must be careful to make certain the calling signature of the
|
||||||
|
function does not cause parameters to be passed on the stack (e.g.:
|
||||||
|
more than eight function arguments, an argument of more than sixteen
|
||||||
|
bytes, or more than 64 bytes of argument data, depending on
|
||||||
|
architecture).
|
||||||
|
|
||||||
1.3 Return Probes
|
1.3 Return Probes
|
||||||
|
|
||||||
1.3.1 How Does a Return Probe Work?
|
1.3.1 How Does a Return Probe Work?
|
||||||
|
@@ -10,7 +10,8 @@ FILES = audio.h.rst ca.h.rst dmx.h.rst frontend.h.rst net.h.rst video.h.rst \
|
|||||||
|
|
||||||
TARGETS := $(addprefix $(BUILDDIR)/, $(FILES))
|
TARGETS := $(addprefix $(BUILDDIR)/, $(FILES))
|
||||||
|
|
||||||
htmldocs: $(BUILDDIR) ${TARGETS}
|
.PHONY: all
|
||||||
|
all: $(BUILDDIR) ${TARGETS}
|
||||||
|
|
||||||
$(BUILDDIR):
|
$(BUILDDIR):
|
||||||
$(Q)mkdir -p $@
|
$(Q)mkdir -p $@
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
ignore define _DVBAUDIO_H_
|
ignore define _DVBAUDIO_H_
|
||||||
|
|
||||||
# Typedef pointing to structs
|
# Typedef pointing to structs
|
||||||
replace typedef audio_karaoke_t audio-karaoke
|
replace typedef audio_karaoke_t :c:type:`audio_karaoke`
|
||||||
|
|
||||||
# Undocumented audio caps, as this is a deprecated API anyway
|
# Undocumented audio caps, as this is a deprecated API anyway
|
||||||
ignore define AUDIO_CAP_DTS
|
ignore define AUDIO_CAP_DTS
|
||||||
@@ -16,5 +16,5 @@ ignore define AUDIO_CAP_SDDS
|
|||||||
ignore define AUDIO_CAP_AC3
|
ignore define AUDIO_CAP_AC3
|
||||||
|
|
||||||
# some typedefs should point to struct/enums
|
# some typedefs should point to struct/enums
|
||||||
replace typedef audio_mixer_t audio-mixer
|
replace typedef audio_mixer_t :c:type:`audio_mixer`
|
||||||
replace typedef audio_status_t audio-status
|
replace typedef audio_status_t :c:type:`audio_status`
|
||||||
|
@@ -2,23 +2,23 @@
|
|||||||
ignore define _DVBCA_H_
|
ignore define _DVBCA_H_
|
||||||
|
|
||||||
# struct ca_slot_info defines
|
# struct ca_slot_info defines
|
||||||
replace define CA_CI ca-slot-info
|
replace define CA_CI :c:type:`ca_slot_info`
|
||||||
replace define CA_CI_LINK ca-slot-info
|
replace define CA_CI_LINK :c:type:`ca_slot_info`
|
||||||
replace define CA_CI_PHYS ca-slot-info
|
replace define CA_CI_PHYS :c:type:`ca_slot_info`
|
||||||
replace define CA_DESCR ca-slot-info
|
replace define CA_DESCR :c:type:`ca_slot_info`
|
||||||
replace define CA_SC ca-slot-info
|
replace define CA_SC :c:type:`ca_slot_info`
|
||||||
replace define CA_CI_MODULE_PRESENT ca-slot-info
|
replace define CA_CI_MODULE_PRESENT :c:type:`ca_slot_info`
|
||||||
replace define CA_CI_MODULE_READY ca-slot-info
|
replace define CA_CI_MODULE_READY :c:type:`ca_slot_info`
|
||||||
|
|
||||||
# struct ca_descr_info defines
|
# struct ca_descr_info defines
|
||||||
replace define CA_ECD ca-descr-info
|
replace define CA_ECD :c:type:`ca_descr_info`
|
||||||
replace define CA_NDS ca-descr-info
|
replace define CA_NDS :c:type:`ca_descr_info`
|
||||||
replace define CA_DSS ca-descr-info
|
replace define CA_DSS :c:type:`ca_descr_info`
|
||||||
|
|
||||||
# some typedefs should point to struct/enums
|
# some typedefs should point to struct/enums
|
||||||
replace typedef ca_pid_t ca-pid
|
replace typedef ca_pid_t :c:type:`ca_pid`
|
||||||
replace typedef ca_slot_info_t ca-slot-info
|
replace typedef ca_slot_info_t :c:type:`ca_slot_info`
|
||||||
replace typedef ca_descr_info_t ca-descr-info
|
replace typedef ca_descr_info_t :c:type:`ca_descr_info`
|
||||||
replace typedef ca_caps_t ca-caps
|
replace typedef ca_caps_t :c:type:`ca_caps`
|
||||||
replace typedef ca_msg_t ca-msg
|
replace typedef ca_msg_t :c:type:`ca_msg`
|
||||||
replace typedef ca_descr_t ca-descr
|
replace typedef ca_descr_t :c:type:`ca_descr`
|
||||||
|
@@ -1,12 +1,6 @@
|
|||||||
# Ignore header name
|
# Ignore header name
|
||||||
ignore define _CEC_UAPI_H
|
ignore define _CEC_UAPI_H
|
||||||
|
|
||||||
# Rename some symbols, to avoid namespace conflicts
|
|
||||||
replace struct cec_event_state_change cec-event-state-change_s
|
|
||||||
replace struct cec_event_lost_msgs cec-event-lost-msgs_s
|
|
||||||
replace enum cec_mode_initiator cec-mode-initiator_e
|
|
||||||
replace enum cec_mode_follower cec-mode-follower_e
|
|
||||||
|
|
||||||
# define macros to ignore
|
# define macros to ignore
|
||||||
|
|
||||||
ignore define CEC_MAX_MSG_SIZE
|
ignore define CEC_MAX_MSG_SIZE
|
||||||
|
10
Documentation/media/conf.py
Normal file
10
Documentation/media/conf.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8; mode: python -*-
|
||||||
|
|
||||||
|
project = 'Linux Media Subsystem Documentation'
|
||||||
|
|
||||||
|
tags.add("subproject")
|
||||||
|
|
||||||
|
latex_documents = [
|
||||||
|
('index', 'media.tex', 'Linux Media Subsystem Documentation',
|
||||||
|
'The kernel development community', 'manual'),
|
||||||
|
]
|
109
Documentation/media/conf_nitpick.py
Normal file
109
Documentation/media/conf_nitpick.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# -*- coding: utf-8; mode: python -*-
|
||||||
|
|
||||||
|
project = 'Linux Media Subsystem Documentation'
|
||||||
|
|
||||||
|
# It is possible to run Sphinx in nickpick mode with:
|
||||||
|
nitpicky = True
|
||||||
|
|
||||||
|
# within nit-picking build, do not refer to any intersphinx object
|
||||||
|
intersphinx_mapping = {}
|
||||||
|
|
||||||
|
# In nickpick mode, it will complain about lots of missing references that
|
||||||
|
#
|
||||||
|
# 1) are just typedefs like: bool, __u32, etc;
|
||||||
|
# 2) It will complain for things like: enum, NULL;
|
||||||
|
# 3) It will complain for symbols that should be on different
|
||||||
|
# books (but currently aren't ported to ReST)
|
||||||
|
#
|
||||||
|
# The list below has a list of such symbols to be ignored in nitpick mode
|
||||||
|
#
|
||||||
|
nitpick_ignore = [
|
||||||
|
("c:func", "clock_gettime"),
|
||||||
|
("c:func", "close"),
|
||||||
|
("c:func", "container_of"),
|
||||||
|
("c:func", "copy_from_user"),
|
||||||
|
("c:func", "copy_to_user"),
|
||||||
|
("c:func", "determine_valid_ioctls"),
|
||||||
|
("c:func", "ERR_PTR"),
|
||||||
|
("c:func", "i2c_new_device"),
|
||||||
|
("c:func", "ioctl"),
|
||||||
|
("c:func", "IS_ERR"),
|
||||||
|
("c:func", "KERNEL_VERSION"),
|
||||||
|
("c:func", "mmap"),
|
||||||
|
("c:func", "open"),
|
||||||
|
("c:func", "pci_name"),
|
||||||
|
("c:func", "poll"),
|
||||||
|
("c:func", "PTR_ERR"),
|
||||||
|
("c:func", "read"),
|
||||||
|
("c:func", "release"),
|
||||||
|
("c:func", "set"),
|
||||||
|
("c:func", "struct fd_set"),
|
||||||
|
("c:func", "struct pollfd"),
|
||||||
|
("c:func", "usb_make_path"),
|
||||||
|
("c:func", "wait_finish"),
|
||||||
|
("c:func", "wait_prepare"),
|
||||||
|
("c:func", "write"),
|
||||||
|
|
||||||
|
("c:type", "atomic_t"),
|
||||||
|
("c:type", "bool"),
|
||||||
|
("c:type", "boolean"),
|
||||||
|
("c:type", "buf_queue"),
|
||||||
|
("c:type", "device"),
|
||||||
|
("c:type", "device_driver"),
|
||||||
|
("c:type", "device_node"),
|
||||||
|
("c:type", "enum"),
|
||||||
|
("c:type", "fd"),
|
||||||
|
("c:type", "fd_set"),
|
||||||
|
("c:type", "file"),
|
||||||
|
("c:type", "i2c_adapter"),
|
||||||
|
("c:type", "i2c_board_info"),
|
||||||
|
("c:type", "i2c_client"),
|
||||||
|
("c:type", "int16_t"),
|
||||||
|
("c:type", "ktime_t"),
|
||||||
|
("c:type", "led_classdev_flash"),
|
||||||
|
("c:type", "list_head"),
|
||||||
|
("c:type", "lock_class_key"),
|
||||||
|
("c:type", "module"),
|
||||||
|
("c:type", "mutex"),
|
||||||
|
("c:type", "NULL"),
|
||||||
|
("c:type", "off_t"),
|
||||||
|
("c:type", "pci_dev"),
|
||||||
|
("c:type", "pdvbdev"),
|
||||||
|
("c:type", "poll_table"),
|
||||||
|
("c:type", "platform_device"),
|
||||||
|
("c:type", "pollfd"),
|
||||||
|
("c:type", "poll_table_struct"),
|
||||||
|
("c:type", "s32"),
|
||||||
|
("c:type", "s64"),
|
||||||
|
("c:type", "sd"),
|
||||||
|
("c:type", "size_t"),
|
||||||
|
("c:type", "spi_board_info"),
|
||||||
|
("c:type", "spi_device"),
|
||||||
|
("c:type", "spi_master"),
|
||||||
|
("c:type", "ssize_t"),
|
||||||
|
("c:type", "fb_fix_screeninfo"),
|
||||||
|
("c:type", "pollfd"),
|
||||||
|
("c:type", "timeval"),
|
||||||
|
("c:type", "video_capability"),
|
||||||
|
("c:type", "timeval"),
|
||||||
|
("c:type", "__u16"),
|
||||||
|
("c:type", "u16"),
|
||||||
|
("c:type", "__u32"),
|
||||||
|
("c:type", "u32"),
|
||||||
|
("c:type", "__u64"),
|
||||||
|
("c:type", "u64"),
|
||||||
|
("c:type", "u8"),
|
||||||
|
("c:type", "uint16_t"),
|
||||||
|
("c:type", "uint32_t"),
|
||||||
|
("c:type", "union"),
|
||||||
|
("c:type", "__user"),
|
||||||
|
("c:type", "usb_device"),
|
||||||
|
("c:type", "usb_interface"),
|
||||||
|
("c:type", "v4l2_std_id"),
|
||||||
|
("c:type", "video_system_t"),
|
||||||
|
("c:type", "vm_area_struct"),
|
||||||
|
|
||||||
|
# Opaque structures
|
||||||
|
|
||||||
|
("c:type", "v4l2_m2m_dev"),
|
||||||
|
]
|
@@ -4,29 +4,29 @@ ignore define _UAPI_DVBDMX_H_
|
|||||||
# Ignore limit constants
|
# Ignore limit constants
|
||||||
ignore define DMX_FILTER_SIZE
|
ignore define DMX_FILTER_SIZE
|
||||||
|
|
||||||
# dmx-pes-type-t enum symbols
|
# dmx_pes_type_t enum symbols
|
||||||
replace enum dmx_ts_pes dmx-pes-type-t
|
replace enum dmx_ts_pes :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_AUDIO0 dmx-pes-type-t
|
replace symbol DMX_PES_AUDIO0 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_VIDEO0 dmx-pes-type-t
|
replace symbol DMX_PES_VIDEO0 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_TELETEXT0 dmx-pes-type-t
|
replace symbol DMX_PES_TELETEXT0 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_SUBTITLE0 dmx-pes-type-t
|
replace symbol DMX_PES_SUBTITLE0 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_PCR0 dmx-pes-type-t
|
replace symbol DMX_PES_PCR0 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_AUDIO1 dmx-pes-type-t
|
replace symbol DMX_PES_AUDIO1 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_VIDEO1 dmx-pes-type-t
|
replace symbol DMX_PES_VIDEO1 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_TELETEXT1 dmx-pes-type-t
|
replace symbol DMX_PES_TELETEXT1 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_SUBTITLE1 dmx-pes-type-t
|
replace symbol DMX_PES_SUBTITLE1 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_PCR1 dmx-pes-type-t
|
replace symbol DMX_PES_PCR1 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_AUDIO2 dmx-pes-type-t
|
replace symbol DMX_PES_AUDIO2 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_VIDEO2 dmx-pes-type-t
|
replace symbol DMX_PES_VIDEO2 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_TELETEXT2 dmx-pes-type-t
|
replace symbol DMX_PES_TELETEXT2 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_SUBTITLE2 dmx-pes-type-t
|
replace symbol DMX_PES_SUBTITLE2 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_PCR2 dmx-pes-type-t
|
replace symbol DMX_PES_PCR2 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_AUDIO3 dmx-pes-type-t
|
replace symbol DMX_PES_AUDIO3 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_VIDEO3 dmx-pes-type-t
|
replace symbol DMX_PES_VIDEO3 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_TELETEXT3 dmx-pes-type-t
|
replace symbol DMX_PES_TELETEXT3 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_SUBTITLE3 dmx-pes-type-t
|
replace symbol DMX_PES_SUBTITLE3 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_PCR3 dmx-pes-type-t
|
replace symbol DMX_PES_PCR3 :c:type:`dmx_pes_type`
|
||||||
replace symbol DMX_PES_OTHER dmx-pes-type-t
|
replace symbol DMX_PES_OTHER :c:type:`dmx_pes_type`
|
||||||
|
|
||||||
# Ignore obsolete symbols
|
# Ignore obsolete symbols
|
||||||
ignore define DMX_PES_AUDIO
|
ignore define DMX_PES_AUDIO
|
||||||
@@ -36,28 +36,31 @@ ignore define DMX_PES_SUBTITLE
|
|||||||
ignore define DMX_PES_PCR
|
ignore define DMX_PES_PCR
|
||||||
|
|
||||||
# dmx_input_t symbols
|
# dmx_input_t symbols
|
||||||
replace enum dmx_input dmx-input-t
|
replace enum dmx_input :c:type:`dmx_input`
|
||||||
replace symbol DMX_IN_FRONTEND dmx-input-t
|
replace symbol DMX_IN_FRONTEND :c:type:`dmx_input`
|
||||||
replace symbol DMX_IN_DVR dmx-input-t
|
replace symbol DMX_IN_DVR :c:type:`dmx_input`
|
||||||
|
|
||||||
# dmx_source_t symbols
|
# dmx_source_t symbols
|
||||||
replace enum dmx_source dmx-source-t
|
replace enum dmx_source :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_FRONT0 dmx-source-t
|
replace symbol DMX_SOURCE_FRONT0 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_FRONT1 dmx-source-t
|
replace symbol DMX_SOURCE_FRONT1 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_FRONT2 dmx-source-t
|
replace symbol DMX_SOURCE_FRONT2 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_FRONT3 dmx-source-t
|
replace symbol DMX_SOURCE_FRONT3 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_DVR0 dmx-source-t
|
replace symbol DMX_SOURCE_DVR0 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_DVR1 dmx-source-t
|
replace symbol DMX_SOURCE_DVR1 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_DVR2 dmx-source-t
|
replace symbol DMX_SOURCE_DVR2 :c:type:`dmx_source`
|
||||||
replace symbol DMX_SOURCE_DVR3 dmx-source-t
|
replace symbol DMX_SOURCE_DVR3 :c:type:`dmx_source`
|
||||||
|
|
||||||
|
|
||||||
# Flags for struct dmx_sct_filter_params
|
# Flags for struct dmx_sct_filter_params
|
||||||
replace define DMX_CHECK_CRC dmx-sct-filter-params
|
replace define DMX_CHECK_CRC :c:type:`dmx_sct_filter_params`
|
||||||
replace define DMX_ONESHOT dmx-sct-filter-params
|
replace define DMX_ONESHOT :c:type:`dmx_sct_filter_params`
|
||||||
replace define DMX_IMMEDIATE_START dmx-sct-filter-params
|
replace define DMX_IMMEDIATE_START :c:type:`dmx_sct_filter_params`
|
||||||
replace define DMX_KERNEL_CLIENT dmx-sct-filter-params
|
replace define DMX_KERNEL_CLIENT :c:type:`dmx_sct_filter_params`
|
||||||
|
|
||||||
# some typedefs should point to struct/enums
|
# some typedefs should point to struct/enums
|
||||||
replace typedef dmx_caps_t dmx-caps
|
replace typedef dmx_caps_t :c:type:`dmx_caps`
|
||||||
replace typedef dmx_filter_t dmx-filter
|
replace typedef dmx_filter_t :c:type:`dmx_filter`
|
||||||
|
replace typedef dmx_pes_type_t :c:type:`dmx_pes_type`
|
||||||
|
replace typedef dmx_input_t :c:type:`dmx_input`
|
||||||
|
replace typedef dmx_source_t :c:type:`dmx_source`
|
||||||
|
@@ -26,22 +26,22 @@ ignore define MAX_DTV_STATS
|
|||||||
ignore define DTV_IOCTL_MAX_MSGS
|
ignore define DTV_IOCTL_MAX_MSGS
|
||||||
|
|
||||||
# Stats enum is documented altogether
|
# Stats enum is documented altogether
|
||||||
replace enum fecap_scale_params frontend-stat-properties
|
replace enum fecap_scale_params :ref:`frontend-stat-properties`
|
||||||
replace symbol FE_SCALE_COUNTER frontend-stat-properties
|
replace symbol FE_SCALE_COUNTER frontend-stat-properties
|
||||||
replace symbol FE_SCALE_DECIBEL frontend-stat-properties
|
replace symbol FE_SCALE_DECIBEL frontend-stat-properties
|
||||||
replace symbol FE_SCALE_NOT_AVAILABLE frontend-stat-properties
|
replace symbol FE_SCALE_NOT_AVAILABLE frontend-stat-properties
|
||||||
replace symbol FE_SCALE_RELATIVE frontend-stat-properties
|
replace symbol FE_SCALE_RELATIVE frontend-stat-properties
|
||||||
|
|
||||||
# the same reference is used for both get and set ioctls
|
# the same reference is used for both get and set ioctls
|
||||||
replace ioctl FE_SET_PROPERTY FE_GET_PROPERTY
|
replace ioctl FE_SET_PROPERTY :c:type:`FE_GET_PROPERTY`
|
||||||
|
|
||||||
# Ignore struct used only internally at Kernel
|
# Ignore struct used only internally at Kernel
|
||||||
ignore struct dtv_cmds_h
|
ignore struct dtv_cmds_h
|
||||||
|
|
||||||
# Typedefs that use the enum reference
|
# Typedefs that use the enum reference
|
||||||
replace typedef fe_sec_voltage_t fe-sec-voltage
|
replace typedef fe_sec_voltage_t :c:type:`fe_sec_voltage`
|
||||||
|
|
||||||
# Replaces for flag constants
|
# Replaces for flag constants
|
||||||
replace define FE_TUNE_MODE_ONESHOT fe_set_frontend_tune_mode
|
replace define FE_TUNE_MODE_ONESHOT :c:func:`FE_SET_FRONTEND_TUNE_MODE`
|
||||||
replace define LNA_AUTO dtv-lna
|
replace define LNA_AUTO dtv-lna
|
||||||
replace define NO_STREAM_ID_FILTER dtv-stream-id
|
replace define NO_STREAM_ID_FILTER dtv-stream-id
|
||||||
|
24
Documentation/media/index.rst
Normal file
24
Documentation/media/index.rst
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Linux Media Subsystem Documentation
|
||||||
|
===================================
|
||||||
|
|
||||||
|
.. Sphinx 1.4.x has a definition for DUrole that doesn't work on alltt blocks
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\renewcommand*{\DUrole}[2]{ #2 }
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
media_uapi
|
||||||
|
media_kapi
|
||||||
|
dvb-drivers/index
|
||||||
|
v4l-drivers/index
|
||||||
|
|
||||||
|
.. only:: subproject
|
||||||
|
|
||||||
|
Indices
|
||||||
|
=======
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
@@ -30,7 +30,7 @@ divided into five parts.
|
|||||||
called as DVB API, in fact it covers several different video standards
|
called as DVB API, in fact it covers several different video standards
|
||||||
including DVB-T/T2, DVB-S/S2, DVB-C, ATSC, ISDB-T, ISDB-S, DTMB, etc. The
|
including DVB-T/T2, DVB-S/S2, DVB-C, ATSC, ISDB-T, ISDB-S, DTMB, etc. The
|
||||||
complete list of supported standards can be found at
|
complete list of supported standards can be found at
|
||||||
:ref:`fe-delivery-system-t`.
|
:c:type:`fe_delivery_system`.
|
||||||
|
|
||||||
3. The :ref:`third part <remote_controllers>` covers the Remote Controller API.
|
3. The :ref:`third part <remote_controllers>` covers the Remote Controller API.
|
||||||
|
|
||||||
|
@@ -36,39 +36,50 @@ CEC Adapter
|
|||||||
The struct cec_adapter represents the CEC adapter hardware. It is created by
|
The struct cec_adapter represents the CEC adapter hardware. It is created by
|
||||||
calling cec_allocate_adapter() and deleted by calling cec_delete_adapter():
|
calling cec_allocate_adapter() and deleted by calling cec_delete_adapter():
|
||||||
|
|
||||||
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
.. c:function::
|
||||||
|
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||||
void *priv, const char *name, u32 caps, u8 available_las,
|
void *priv, const char *name, u32 caps, u8 available_las,
|
||||||
struct device *parent);
|
struct device *parent);
|
||||||
void cec_delete_adapter(struct cec_adapter *adap);
|
|
||||||
|
.. c:function::
|
||||||
|
void cec_delete_adapter(struct cec_adapter *adap);
|
||||||
|
|
||||||
To create an adapter you need to pass the following information:
|
To create an adapter you need to pass the following information:
|
||||||
|
|
||||||
ops: adapter operations which are called by the CEC framework and that you
|
ops:
|
||||||
have to implement.
|
adapter operations which are called by the CEC framework and that you
|
||||||
|
have to implement.
|
||||||
|
|
||||||
priv: will be stored in adap->priv and can be used by the adapter ops.
|
priv:
|
||||||
|
will be stored in adap->priv and can be used by the adapter ops.
|
||||||
|
|
||||||
name: the name of the CEC adapter. Note: this name will be copied.
|
name:
|
||||||
|
the name of the CEC adapter. Note: this name will be copied.
|
||||||
|
|
||||||
caps: capabilities of the CEC adapter. These capabilities determine the
|
caps:
|
||||||
|
capabilities of the CEC adapter. These capabilities determine the
|
||||||
capabilities of the hardware and which parts are to be handled
|
capabilities of the hardware and which parts are to be handled
|
||||||
by userspace and which parts are handled by kernelspace. The
|
by userspace and which parts are handled by kernelspace. The
|
||||||
capabilities are returned by CEC_ADAP_G_CAPS.
|
capabilities are returned by CEC_ADAP_G_CAPS.
|
||||||
|
|
||||||
available_las: the number of simultaneous logical addresses that this
|
available_las:
|
||||||
|
the number of simultaneous logical addresses that this
|
||||||
adapter can handle. Must be 1 <= available_las <= CEC_MAX_LOG_ADDRS.
|
adapter can handle. Must be 1 <= available_las <= CEC_MAX_LOG_ADDRS.
|
||||||
|
|
||||||
parent: the parent device.
|
parent:
|
||||||
|
the parent device.
|
||||||
|
|
||||||
|
|
||||||
To register the /dev/cecX device node and the remote control device (if
|
To register the /dev/cecX device node and the remote control device (if
|
||||||
CEC_CAP_RC is set) you call:
|
CEC_CAP_RC is set) you call:
|
||||||
|
|
||||||
int cec_register_adapter(struct cec_adapter *adap);
|
.. c:function::
|
||||||
|
int cec_register_adapter(struct cec_adapter \*adap);
|
||||||
|
|
||||||
To unregister the devices call:
|
To unregister the devices call:
|
||||||
|
|
||||||
void cec_unregister_adapter(struct cec_adapter *adap);
|
.. c:function::
|
||||||
|
void cec_unregister_adapter(struct cec_adapter \*adap);
|
||||||
|
|
||||||
Note: if cec_register_adapter() fails, then call cec_delete_adapter() to
|
Note: if cec_register_adapter() fails, then call cec_delete_adapter() to
|
||||||
clean up. But if cec_register_adapter() succeeded, then only call
|
clean up. But if cec_register_adapter() succeeded, then only call
|
||||||
@@ -83,18 +94,23 @@ Implementing the Low-Level CEC Adapter
|
|||||||
The following low-level adapter operations have to be implemented in
|
The following low-level adapter operations have to be implemented in
|
||||||
your driver:
|
your driver:
|
||||||
|
|
||||||
struct cec_adap_ops {
|
.. c:type:: struct cec_adap_ops
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
struct cec_adap_ops
|
||||||
|
{
|
||||||
/* Low-level callbacks */
|
/* Low-level callbacks */
|
||||||
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
||||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||||
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
||||||
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||||
u32 signal_free_time, struct cec_msg *msg);
|
u32 signal_free_time, struct cec_msg *msg);
|
||||||
void (*adap_log_status)(struct cec_adapter *adap);
|
void (\*adap_log_status)(struct cec_adapter *adap);
|
||||||
|
|
||||||
/* High-level callbacks */
|
/* High-level callbacks */
|
||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
||||||
The three low-level ops deal with various aspects of controlling the CEC adapter
|
The three low-level ops deal with various aspects of controlling the CEC adapter
|
||||||
hardware:
|
hardware:
|
||||||
@@ -102,6 +118,7 @@ hardware:
|
|||||||
|
|
||||||
To enable/disable the hardware:
|
To enable/disable the hardware:
|
||||||
|
|
||||||
|
.. c:function::
|
||||||
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
||||||
|
|
||||||
This callback enables or disables the CEC hardware. Enabling the CEC hardware
|
This callback enables or disables the CEC hardware. Enabling the CEC hardware
|
||||||
@@ -115,6 +132,7 @@ Note that adap_enable must return 0 if enable is false.
|
|||||||
|
|
||||||
To enable/disable the 'monitor all' mode:
|
To enable/disable the 'monitor all' mode:
|
||||||
|
|
||||||
|
.. c:function::
|
||||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||||
|
|
||||||
If enabled, then the adapter should be put in a mode to also monitor messages
|
If enabled, then the adapter should be put in a mode to also monitor messages
|
||||||
@@ -127,6 +145,7 @@ Note that adap_monitor_all_enable must return 0 if enable is false.
|
|||||||
|
|
||||||
To program a new logical address:
|
To program a new logical address:
|
||||||
|
|
||||||
|
.. c:function::
|
||||||
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
||||||
|
|
||||||
If logical_addr == CEC_LOG_ADDR_INVALID then all programmed logical addresses
|
If logical_addr == CEC_LOG_ADDR_INVALID then all programmed logical addresses
|
||||||
@@ -140,6 +159,7 @@ Note that adap_log_addr must return 0 if logical_addr is CEC_LOG_ADDR_INVALID.
|
|||||||
|
|
||||||
To transmit a new message:
|
To transmit a new message:
|
||||||
|
|
||||||
|
.. c:function::
|
||||||
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||||
u32 signal_free_time, struct cec_msg *msg);
|
u32 signal_free_time, struct cec_msg *msg);
|
||||||
|
|
||||||
@@ -158,6 +178,7 @@ microseconds (one data bit period is 2.4 ms).
|
|||||||
|
|
||||||
To log the current CEC hardware status:
|
To log the current CEC hardware status:
|
||||||
|
|
||||||
|
.. c:function::
|
||||||
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
||||||
|
|
||||||
This optional callback can be used to show the status of the CEC hardware.
|
This optional callback can be used to show the status of the CEC hardware.
|
||||||
@@ -169,29 +190,41 @@ driven) by calling into the framework in the following situations:
|
|||||||
|
|
||||||
When a transmit finished (successfully or otherwise):
|
When a transmit finished (successfully or otherwise):
|
||||||
|
|
||||||
void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
|
.. c:function::
|
||||||
|
void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
|
||||||
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
|
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
|
||||||
|
|
||||||
The status can be one of:
|
The status can be one of:
|
||||||
|
|
||||||
CEC_TX_STATUS_OK: the transmit was successful.
|
CEC_TX_STATUS_OK:
|
||||||
CEC_TX_STATUS_ARB_LOST: arbitration was lost: another CEC initiator
|
the transmit was successful.
|
||||||
took control of the CEC line and you lost the arbitration.
|
|
||||||
CEC_TX_STATUS_NACK: the message was nacked (for a directed message) or
|
|
||||||
acked (for a broadcast message). A retransmission is needed.
|
|
||||||
CEC_TX_STATUS_LOW_DRIVE: low drive was detected on the CEC bus. This
|
|
||||||
indicates that a follower detected an error on the bus and requested a
|
|
||||||
retransmission.
|
|
||||||
CEC_TX_STATUS_ERROR: some unspecified error occurred: this can be one of
|
|
||||||
the previous two if the hardware cannot differentiate or something else
|
|
||||||
entirely.
|
|
||||||
CEC_TX_STATUS_MAX_RETRIES: could not transmit the message after
|
|
||||||
trying multiple times. Should only be set by the driver if it has hardware
|
|
||||||
support for retrying messages. If set, then the framework assumes that it
|
|
||||||
doesn't have to make another attempt to transmit the message since the
|
|
||||||
hardware did that already.
|
|
||||||
|
|
||||||
The *_cnt arguments are the number of error conditions that were seen.
|
CEC_TX_STATUS_ARB_LOST:
|
||||||
|
arbitration was lost: another CEC initiator
|
||||||
|
took control of the CEC line and you lost the arbitration.
|
||||||
|
|
||||||
|
CEC_TX_STATUS_NACK:
|
||||||
|
the message was nacked (for a directed message) or
|
||||||
|
acked (for a broadcast message). A retransmission is needed.
|
||||||
|
|
||||||
|
CEC_TX_STATUS_LOW_DRIVE:
|
||||||
|
low drive was detected on the CEC bus. This indicates that
|
||||||
|
a follower detected an error on the bus and requested a
|
||||||
|
retransmission.
|
||||||
|
|
||||||
|
CEC_TX_STATUS_ERROR:
|
||||||
|
some unspecified error occurred: this can be one of
|
||||||
|
the previous two if the hardware cannot differentiate or something
|
||||||
|
else entirely.
|
||||||
|
|
||||||
|
CEC_TX_STATUS_MAX_RETRIES:
|
||||||
|
could not transmit the message after trying multiple times.
|
||||||
|
Should only be set by the driver if it has hardware support for
|
||||||
|
retrying messages. If set, then the framework assumes that it
|
||||||
|
doesn't have to make another attempt to transmit the message
|
||||||
|
since the hardware did that already.
|
||||||
|
|
||||||
|
The \*_cnt arguments are the number of error conditions that were seen.
|
||||||
This may be 0 if no information is available. Drivers that do not support
|
This may be 0 if no information is available. Drivers that do not support
|
||||||
hardware retry can just set the counter corresponding to the transmit error
|
hardware retry can just set the counter corresponding to the transmit error
|
||||||
to 1, if the hardware does support retry then either set these counters to
|
to 1, if the hardware does support retry then either set these counters to
|
||||||
@@ -200,7 +233,8 @@ times, or fill in the correct values as reported by the hardware.
|
|||||||
|
|
||||||
When a CEC message was received:
|
When a CEC message was received:
|
||||||
|
|
||||||
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
|
.. c:function::
|
||||||
|
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
|
||||||
|
|
||||||
Speaks for itself.
|
Speaks for itself.
|
||||||
|
|
||||||
@@ -210,17 +244,20 @@ Implementing the High-Level CEC Adapter
|
|||||||
The low-level operations drive the hardware, the high-level operations are
|
The low-level operations drive the hardware, the high-level operations are
|
||||||
CEC protocol driven. The following high-level callbacks are available:
|
CEC protocol driven. The following high-level callbacks are available:
|
||||||
|
|
||||||
struct cec_adap_ops {
|
.. code-block:: none
|
||||||
/* Low-level callbacks */
|
|
||||||
|
struct cec_adap_ops {
|
||||||
|
/\* Low-level callbacks \*/
|
||||||
...
|
...
|
||||||
|
|
||||||
/* High-level CEC message callback */
|
/\* High-level CEC message callback \*/
|
||||||
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
int (\*received)(struct cec_adapter \*adap, struct cec_msg \*msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
The received() callback allows the driver to optionally handle a newly
|
The received() callback allows the driver to optionally handle a newly
|
||||||
received CEC message
|
received CEC message
|
||||||
|
|
||||||
|
.. c:function::
|
||||||
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
||||||
|
|
||||||
If the driver wants to process a CEC message, then it can implement this
|
If the driver wants to process a CEC message, then it can implement this
|
||||||
@@ -234,13 +271,16 @@ CEC framework functions
|
|||||||
|
|
||||||
CEC Adapter drivers can call the following CEC framework functions:
|
CEC Adapter drivers can call the following CEC framework functions:
|
||||||
|
|
||||||
int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
|
.. c:function::
|
||||||
|
int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
|
||||||
bool block);
|
bool block);
|
||||||
|
|
||||||
Transmit a CEC message. If block is true, then wait until the message has been
|
Transmit a CEC message. If block is true, then wait until the message has been
|
||||||
transmitted, otherwise just queue it and return.
|
transmitted, otherwise just queue it and return.
|
||||||
|
|
||||||
void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block);
|
.. c:function::
|
||||||
|
void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr,
|
||||||
|
bool block);
|
||||||
|
|
||||||
Change the physical address. This function will set adap->phys_addr and
|
Change the physical address. This function will set adap->phys_addr and
|
||||||
send an event if it has changed. If cec_s_log_addrs() has been called and
|
send an event if it has changed. If cec_s_log_addrs() has been called and
|
||||||
@@ -254,7 +294,8 @@ then the CEC adapter will be disabled. If you change a valid physical address
|
|||||||
to another valid physical address, then this function will first set the
|
to another valid physical address, then this function will first set the
|
||||||
address to CEC_PHYS_ADDR_INVALID before enabling the new physical address.
|
address to CEC_PHYS_ADDR_INVALID before enabling the new physical address.
|
||||||
|
|
||||||
int cec_s_log_addrs(struct cec_adapter *adap,
|
.. c:function::
|
||||||
|
int cec_s_log_addrs(struct cec_adapter *adap,
|
||||||
struct cec_log_addrs *log_addrs, bool block);
|
struct cec_log_addrs *log_addrs, bool block);
|
||||||
|
|
||||||
Claim the CEC logical addresses. Should never be called if CEC_CAP_LOG_ADDRS
|
Claim the CEC logical addresses. Should never be called if CEC_CAP_LOG_ADDRS
|
@@ -6,8 +6,6 @@ Digital TV Common functions
|
|||||||
|
|
||||||
.. kernel-doc:: drivers/media/dvb-core/dvb_math.h
|
.. kernel-doc:: drivers/media/dvb-core/dvb_math.h
|
||||||
|
|
||||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h
|
|
||||||
|
|
||||||
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +16,42 @@ Digital TV Common functions
|
|||||||
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
||||||
:export: drivers/media/dvb-core/dvbdev.c
|
:export: drivers/media/dvb-core/dvbdev.c
|
||||||
|
|
||||||
|
Digital TV Ring buffer
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Those routines implement ring buffers used to handle digital TV data and
|
||||||
|
copy it from/to userspace.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
1) For performance reasons read and write routines don't check buffer sizes
|
||||||
|
and/or number of bytes free/available. This has to be done before these
|
||||||
|
routines are called. For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
/* write @buflen: bytes */
|
||||||
|
free = dvb_ringbuffer_free(rbuf);
|
||||||
|
if (free >= buflen)
|
||||||
|
count = dvb_ringbuffer_write(rbuf, buffer, buflen);
|
||||||
|
else
|
||||||
|
/* do something */
|
||||||
|
|
||||||
|
/* read min. 1000, max. @bufsize: bytes */
|
||||||
|
avail = dvb_ringbuffer_avail(rbuf);
|
||||||
|
if (avail >= 1000)
|
||||||
|
count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
|
||||||
|
else
|
||||||
|
/* do something */
|
||||||
|
|
||||||
|
2) If there is exactly one reader and one writer, there is no need
|
||||||
|
to lock read or write operations.
|
||||||
|
Two or more readers must be locked against each other.
|
||||||
|
Flushing the buffer counts as a read operation.
|
||||||
|
Resetting the buffer counts as a read and write operation.
|
||||||
|
Two or more writers must be locked against each other.
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h
|
||||||
|
|
||||||
|
|
||||||
Digital TV Frontend kABI
|
Digital TV Frontend kABI
|
||||||
@@ -121,7 +155,7 @@ triggered by a hardware interrupt, it is recommended to use the Linux
|
|||||||
bottom half mechanism or start a tasklet instead of making the callback
|
bottom half mechanism or start a tasklet instead of making the callback
|
||||||
function call directly from a hardware interrupt.
|
function call directly from a hardware interrupt.
|
||||||
|
|
||||||
This mechanism is implemented by :c:func:`dmx_ts_cb()` and :cpp:func:`dmx_section_cb()`
|
This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()`
|
||||||
callbacks.
|
callbacks.
|
||||||
|
|
||||||
.. kernel-doc:: drivers/media/dvb-core/demux.h
|
.. kernel-doc:: drivers/media/dvb-core/demux.h
|
||||||
|
@@ -34,7 +34,7 @@ pad to a sink pad.
|
|||||||
Media device
|
Media device
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
A media device is represented by a :c:type:`struct media_device <media_device>`
|
A media device is represented by a struct :c:type:`media_device`
|
||||||
instance, defined in ``include/media/media-device.h``.
|
instance, defined in ``include/media/media-device.h``.
|
||||||
Allocation of the structure is handled by the media device driver, usually by
|
Allocation of the structure is handled by the media device driver, usually by
|
||||||
embedding the :c:type:`media_device` instance in a larger driver-specific
|
embedding the :c:type:`media_device` instance in a larger driver-specific
|
||||||
@@ -47,7 +47,7 @@ and unregistered by calling :c:func:`media_device_unregister()`.
|
|||||||
Entities
|
Entities
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
Entities are represented by a :c:type:`struct media_entity <media_entity>`
|
Entities are represented by a struct :c:type:`media_entity`
|
||||||
instance, defined in ``include/media/media-entity.h``. The structure is usually
|
instance, defined in ``include/media/media-entity.h``. The structure is usually
|
||||||
embedded into a higher-level structure, such as
|
embedded into a higher-level structure, such as
|
||||||
:c:type:`v4l2_subdev` or :c:type:`video_device`
|
:c:type:`v4l2_subdev` or :c:type:`video_device`
|
||||||
@@ -65,10 +65,10 @@ Interfaces
|
|||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
Interfaces are represented by a
|
Interfaces are represented by a
|
||||||
:c:type:`struct media_interface <media_interface>` instance, defined in
|
struct :c:type:`media_interface` instance, defined in
|
||||||
``include/media/media-entity.h``. Currently, only one type of interface is
|
``include/media/media-entity.h``. Currently, only one type of interface is
|
||||||
defined: a device node. Such interfaces are represented by a
|
defined: a device node. Such interfaces are represented by a
|
||||||
:c:type:`struct media_intf_devnode <media_intf_devnode>`.
|
struct :c:type:`media_intf_devnode`.
|
||||||
|
|
||||||
Drivers initialize and create device node interfaces by calling
|
Drivers initialize and create device node interfaces by calling
|
||||||
:c:func:`media_devnode_create()`
|
:c:func:`media_devnode_create()`
|
||||||
@@ -77,7 +77,7 @@ and remove them by calling:
|
|||||||
|
|
||||||
Pads
|
Pads
|
||||||
^^^^
|
^^^^
|
||||||
Pads are represented by a :c:type:`struct media_pad <media_pad>` instance,
|
Pads are represented by a struct :c:type:`media_pad` instance,
|
||||||
defined in ``include/media/media-entity.h``. Each entity stores its pads in
|
defined in ``include/media/media-entity.h``. Each entity stores its pads in
|
||||||
a pads array managed by the entity driver. Drivers usually embed the array in
|
a pads array managed by the entity driver. Drivers usually embed the array in
|
||||||
a driver-specific structure.
|
a driver-specific structure.
|
||||||
@@ -85,8 +85,9 @@ a driver-specific structure.
|
|||||||
Pads are identified by their entity and their 0-based index in the pads
|
Pads are identified by their entity and their 0-based index in the pads
|
||||||
array.
|
array.
|
||||||
|
|
||||||
Both information are stored in the :c:type:`struct media_pad`, making the
|
Both information are stored in the struct :c:type:`media_pad`,
|
||||||
:c:type:`media_pad` pointer the canonical way to store and pass link references.
|
making the struct :c:type:`media_pad` pointer the canonical way
|
||||||
|
to store and pass link references.
|
||||||
|
|
||||||
Pads have flags that describe the pad capabilities and state.
|
Pads have flags that describe the pad capabilities and state.
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ Pads have flags that describe the pad capabilities and state.
|
|||||||
Links
|
Links
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
Links are represented by a :c:type:`struct media_link <media_link>` instance,
|
Links are represented by a struct :c:type:`media_link` instance,
|
||||||
defined in ``include/media/media-entity.h``. There are two types of links:
|
defined in ``include/media/media-entity.h``. There are two types of links:
|
||||||
|
|
||||||
**1. pad to pad links**:
|
**1. pad to pad links**:
|
||||||
@@ -184,7 +185,7 @@ Use count and power handling
|
|||||||
|
|
||||||
Due to the wide differences between drivers regarding power management
|
Due to the wide differences between drivers regarding power management
|
||||||
needs, the media controller does not implement power management. However,
|
needs, the media controller does not implement power management. However,
|
||||||
the :c:type:`struct media_entity <media_entity>` includes a ``use_count``
|
the struct :c:type:`media_entity` includes a ``use_count``
|
||||||
field that media drivers
|
field that media drivers
|
||||||
can use to track the number of users of every entity for power management
|
can use to track the number of users of every entity for power management
|
||||||
needs.
|
needs.
|
||||||
@@ -210,11 +211,11 @@ prevent link states from being modified during streaming by calling
|
|||||||
The function will mark all entities connected to the given entity through
|
The function will mark all entities connected to the given entity through
|
||||||
enabled links, either directly or indirectly, as streaming.
|
enabled links, either directly or indirectly, as streaming.
|
||||||
|
|
||||||
The :c:type:`struct media_pipeline <media_pipeline>` instance pointed to by
|
The struct :c:type:`media_pipeline` instance pointed to by
|
||||||
the pipe argument will be stored in every entity in the pipeline.
|
the pipe argument will be stored in every entity in the pipeline.
|
||||||
Drivers should embed the :c:type:`struct media_pipeline <media_pipeline>`
|
Drivers should embed the struct :c:type:`media_pipeline`
|
||||||
in higher-level pipeline structures and can then access the
|
in higher-level pipeline structures and can then access the
|
||||||
pipeline through the :c:type:`struct media_entity <media_entity>`
|
pipeline through the struct :c:type:`media_entity`
|
||||||
pipe field.
|
pipe field.
|
||||||
|
|
||||||
Calls to :c:func:`media_entity_pipeline_start()` can be nested.
|
Calls to :c:func:`media_entity_pipeline_start()` can be nested.
|
||||||
|
@@ -56,7 +56,7 @@ You should also set these fields of :c:type:`video_device`:
|
|||||||
:c:type:`video_device`->vfl_dir fields are used to disable ops that do not
|
:c:type:`video_device`->vfl_dir fields are used to disable ops that do not
|
||||||
match the type/dir combination. E.g. VBI ops are disabled for non-VBI nodes,
|
match the type/dir combination. E.g. VBI ops are disabled for non-VBI nodes,
|
||||||
and output ops are disabled for a capture device. This makes it possible to
|
and output ops are disabled for a capture device. This makes it possible to
|
||||||
provide just one :c:type:`v4l2_ioctl_ops struct` for both vbi and
|
provide just one :c:type:`v4l2_ioctl_ops` struct for both vbi and
|
||||||
video nodes.
|
video nodes.
|
||||||
|
|
||||||
- :c:type:`video_device`->lock: leave to ``NULL`` if you want to do all the
|
- :c:type:`video_device`->lock: leave to ``NULL`` if you want to do all the
|
||||||
@@ -166,14 +166,14 @@ something.
|
|||||||
In the case of :ref:`videobuf2 <vb2_framework>` you will need to implement the
|
In the case of :ref:`videobuf2 <vb2_framework>` you will need to implement the
|
||||||
``wait_prepare()`` and ``wait_finish()`` callbacks to unlock/lock if applicable.
|
``wait_prepare()`` and ``wait_finish()`` callbacks to unlock/lock if applicable.
|
||||||
If you use the ``queue->lock`` pointer, then you can use the helper functions
|
If you use the ``queue->lock`` pointer, then you can use the helper functions
|
||||||
:c:func:`vb2_ops_wait_prepare` and :cpp:func:`vb2_ops_wait_finish`.
|
:c:func:`vb2_ops_wait_prepare` and :c:func:`vb2_ops_wait_finish`.
|
||||||
|
|
||||||
The implementation of a hotplug disconnect should also take the lock from
|
The implementation of a hotplug disconnect should also take the lock from
|
||||||
:c:type:`video_device` before calling v4l2_device_disconnect. If you are also
|
:c:type:`video_device` before calling v4l2_device_disconnect. If you are also
|
||||||
using :c:type:`video_device`->queue->lock, then you have to first lock
|
using :c:type:`video_device`->queue->lock, then you have to first lock
|
||||||
:c:type:`video_device`->queue->lock followed by :c:type:`video_device`->lock.
|
:c:type:`video_device`->queue->lock followed by :c:type:`video_device`->lock.
|
||||||
That way you can be sure no ioctl is running when you call
|
That way you can be sure no ioctl is running when you call
|
||||||
:c:type:`v4l2_device_disconnect`.
|
:c:func:`v4l2_device_disconnect`.
|
||||||
|
|
||||||
Video device registration
|
Video device registration
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -200,6 +200,7 @@ types exist:
|
|||||||
- ``VFL_TYPE_VBI``: ``/dev/vbiX`` for vertical blank data (i.e. closed captions, teletext)
|
- ``VFL_TYPE_VBI``: ``/dev/vbiX`` for vertical blank data (i.e. closed captions, teletext)
|
||||||
- ``VFL_TYPE_RADIO``: ``/dev/radioX`` for radio tuners
|
- ``VFL_TYPE_RADIO``: ``/dev/radioX`` for radio tuners
|
||||||
- ``VFL_TYPE_SDR``: ``/dev/swradioX`` for Software Defined Radio tuners
|
- ``VFL_TYPE_SDR``: ``/dev/swradioX`` for Software Defined Radio tuners
|
||||||
|
- ``VFL_TYPE_TOUCH``: ``/dev/v4l-touchX`` for touch sensors
|
||||||
|
|
||||||
The last argument gives you a certain amount of control over the device
|
The last argument gives you a certain amount of control over the device
|
||||||
device node number used (i.e. the X in ``videoX``). Normally you will pass -1
|
device node number used (i.e. the X in ``videoX``). Normally you will pass -1
|
||||||
@@ -262,6 +263,7 @@ file operations.
|
|||||||
|
|
||||||
It is a bitmask and the following bits can be set:
|
It is a bitmask and the following bits can be set:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{5ex}|L|
|
||||||
|
|
||||||
===== ================================================================
|
===== ================================================================
|
||||||
Mask Description
|
Mask Description
|
||||||
@@ -334,7 +336,7 @@ And this function:
|
|||||||
|
|
||||||
returns the video_device belonging to the file struct.
|
returns the video_device belonging to the file struct.
|
||||||
|
|
||||||
The :c:func:`video_devdata` function combines :cpp:func:`video_get_drvdata`
|
The :c:func:`video_devdata` function combines :c:func:`video_get_drvdata`
|
||||||
with :c:func:`video_devdata`:
|
with :c:func:`video_devdata`:
|
||||||
|
|
||||||
:c:func:`video_drvdata <video_drvdata>`
|
:c:func:`video_drvdata <video_drvdata>`
|
||||||
|
@@ -40,7 +40,7 @@ A good example of these ``replace``/``merge`` callbacks is in v4l2-event.c:
|
|||||||
In order to queue events to video device, drivers should call:
|
In order to queue events to video device, drivers should call:
|
||||||
|
|
||||||
:c:func:`v4l2_event_queue <v4l2_event_queue>`
|
:c:func:`v4l2_event_queue <v4l2_event_queue>`
|
||||||
(:c:type:`vdev <video_device>`, :ref:`ev <v4l2-event>`)
|
(:c:type:`vdev <video_device>`, :c:type:`ev <v4l2_event>`)
|
||||||
|
|
||||||
The driver's only responsibility is to fill in the type and the data fields.
|
The driver's only responsibility is to fill in the type and the data fields.
|
||||||
The other fields will be filled in by V4L2.
|
The other fields will be filled in by V4L2.
|
||||||
@@ -51,7 +51,7 @@ Event subscription
|
|||||||
Subscribing to an event is via:
|
Subscribing to an event is via:
|
||||||
|
|
||||||
:c:func:`v4l2_event_subscribe <v4l2_event_subscribe>`
|
:c:func:`v4l2_event_subscribe <v4l2_event_subscribe>`
|
||||||
(:c:type:`fh <v4l2_fh>`, :ref:`sub <v4l2-event-subscription>` ,
|
(:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>` ,
|
||||||
elems, :c:type:`ops <v4l2_subscribed_event_ops>`)
|
elems, :c:type:`ops <v4l2_subscribed_event_ops>`)
|
||||||
|
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ Unsubscribing an event
|
|||||||
Unsubscribing to an event is via:
|
Unsubscribing to an event is via:
|
||||||
|
|
||||||
:c:func:`v4l2_event_unsubscribe <v4l2_event_unsubscribe>`
|
:c:func:`v4l2_event_unsubscribe <v4l2_event_unsubscribe>`
|
||||||
(:c:type:`fh <v4l2_fh>`, :ref:`sub <v4l2-event-subscription>`)
|
(:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>`)
|
||||||
|
|
||||||
This function is used to implement :c:type:`video_device`->
|
This function is used to implement :c:type:`video_device`->
|
||||||
:c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_unsubscribe_event``.
|
:c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_unsubscribe_event``.
|
||||||
|
@@ -21,8 +21,8 @@ function by the driver.
|
|||||||
In many cases the struct :c:type:`v4l2_fh` will be embedded in a larger
|
In many cases the struct :c:type:`v4l2_fh` will be embedded in a larger
|
||||||
structure. In that case you should call:
|
structure. In that case you should call:
|
||||||
|
|
||||||
#) :c:func:`v4l2_fh_init` and :cpp:func:`v4l2_fh_add` in ``open()``
|
#) :c:func:`v4l2_fh_init` and :c:func:`v4l2_fh_add` in ``open()``
|
||||||
#) :c:func:`v4l2_fh_del` and :cpp:func:`v4l2_fh_exit` in ``release()``
|
#) :c:func:`v4l2_fh_del` and :c:func:`v4l2_fh_exit` in ``release()``
|
||||||
|
|
||||||
Drivers can extract their own file handle structure by using the container_of
|
Drivers can extract their own file handle structure by using the container_of
|
||||||
macro.
|
macro.
|
||||||
|
@@ -27,7 +27,7 @@ methods.
|
|||||||
Bridges might also need to store per-subdev private data, such as a pointer to
|
Bridges might also need to store per-subdev private data, such as a pointer to
|
||||||
bridge-specific per-subdev private data. The :c:type:`v4l2_subdev` structure
|
bridge-specific per-subdev private data. The :c:type:`v4l2_subdev` structure
|
||||||
provides host private data for that purpose that can be accessed with
|
provides host private data for that purpose that can be accessed with
|
||||||
:c:func:`v4l2_get_subdev_hostdata` and :cpp:func:`v4l2_set_subdev_hostdata`.
|
:c:func:`v4l2_get_subdev_hostdata` and :c:func:`v4l2_set_subdev_hostdata`.
|
||||||
|
|
||||||
From the bridge driver perspective, you load the sub-device module and somehow
|
From the bridge driver perspective, you load the sub-device module and somehow
|
||||||
obtain the :c:type:`v4l2_subdev` pointer. For i2c devices this is easy: you call
|
obtain the :c:type:`v4l2_subdev` pointer. For i2c devices this is easy: you call
|
||||||
@@ -412,19 +412,7 @@ later date. It differs between i2c drivers and as such can be confusing.
|
|||||||
To see which chip variants are supported you can look in the i2c driver code
|
To see which chip variants are supported you can look in the i2c driver code
|
||||||
for the i2c_device_id table. This lists all the possibilities.
|
for the i2c_device_id table. This lists all the possibilities.
|
||||||
|
|
||||||
There are two more helper functions:
|
There are one more helper function:
|
||||||
|
|
||||||
:c:func:`v4l2_i2c_new_subdev_cfg`: this function adds new irq and
|
|
||||||
platform_data arguments and has both 'addr' and 'probed_addrs' arguments:
|
|
||||||
if addr is not 0 then that will be used (non-probing variant), otherwise the
|
|
||||||
probed_addrs are probed.
|
|
||||||
|
|
||||||
For example: this will probe for address 0x10:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter,
|
|
||||||
"module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10));
|
|
||||||
|
|
||||||
:c:func:`v4l2_i2c_new_subdev_board` uses an :c:type:`i2c_board_info` struct
|
:c:func:`v4l2_i2c_new_subdev_board` uses an :c:type:`i2c_board_info` struct
|
||||||
which is passed to the i2c driver and replaces the irq, platform_data and addr
|
which is passed to the i2c driver and replaces the irq, platform_data and addr
|
||||||
@@ -433,9 +421,10 @@ arguments.
|
|||||||
If the subdev supports the s_config core ops, then that op is called with
|
If the subdev supports the s_config core ops, then that op is called with
|
||||||
the irq and platform_data arguments after the subdev was setup.
|
the irq and platform_data arguments after the subdev was setup.
|
||||||
|
|
||||||
The older :c:func:`v4l2_i2c_new_subdev` and
|
The :c:func:`v4l2_i2c_new_subdev` function will call
|
||||||
:c:func:`v4l2_i2c_new_probed_subdev` functions will call ``s_config`` as
|
:c:func:`v4l2_i2c_new_subdev_board`, internally filling a
|
||||||
well, but with irq set to 0 and platform_data set to ``NULL``.
|
:c:type:`i2c_board_info` structure using the ``client_type`` and the
|
||||||
|
``addr`` to fill it.
|
||||||
|
|
||||||
V4L2 sub-device functions and data structures
|
V4L2 sub-device functions and data structures
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
Binary file not shown.
@@ -32,3 +32,4 @@ For more details see the file COPYING in the source distribution of Linux.
|
|||||||
kapi/dtv-core
|
kapi/dtv-core
|
||||||
kapi/rc-core
|
kapi/rc-core
|
||||||
kapi/mc-core
|
kapi/mc-core
|
||||||
|
kapi/cec-core
|
||||||
|
@@ -7,5 +7,5 @@ ignore ioctl __NET_GET_IF_OLD
|
|||||||
ignore struct __dvb_net_if_old
|
ignore struct __dvb_net_if_old
|
||||||
|
|
||||||
# Macros used at struct dvb_net_if
|
# Macros used at struct dvb_net_if
|
||||||
replace define DVB_NET_FEEDTYPE_MPE dvb-net-if
|
replace define DVB_NET_FEEDTYPE_MPE :c:type:`dvb_net_if`
|
||||||
replace define DVB_NET_FEEDTYPE_ULE dvb-net-if
|
replace define DVB_NET_FEEDTYPE_ULE :c:type:`dvb_net_if`
|
||||||
|
@@ -20,19 +20,22 @@ Synopsis
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
.. cpp:function:: int close( int fd )
|
.. c:function:: int close( int fd )
|
||||||
|
:name: cec-close
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <func-open>`.
|
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
Closes the cec device. Resources associated with the file descriptor are
|
Closes the cec device. Resources associated with the file descriptor are
|
||||||
|
@@ -19,17 +19,18 @@ Synopsis
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, void *argp )
|
.. c:function:: int ioctl( int fd, int request, void *argp )
|
||||||
|
:name: cec-ioctl
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <func-open>`.
|
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||||
|
|
||||||
``request``
|
``request``
|
||||||
CEC ioctl request code as defined in the cec.h header file, for
|
CEC ioctl request code as defined in the cec.h header file, for
|
||||||
example :ref:`CEC_ADAP_G_CAPS`.
|
example :c:func:`CEC_ADAP_G_CAPS`.
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
Pointer to a request-specific structure.
|
Pointer to a request-specific structure.
|
||||||
@@ -38,7 +39,9 @@ Arguments
|
|||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
The :c:func:`ioctl()` function manipulates cec device parameters. The
|
The :c:func:`ioctl()` function manipulates cec device parameters. The
|
||||||
|
@@ -19,7 +19,8 @@ Synopsis
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
.. cpp:function:: int open( const char *device_name, int flags )
|
.. c:function:: int open( const char *device_name, int flags )
|
||||||
|
:name: cec-open
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -32,7 +33,7 @@ Arguments
|
|||||||
Open flags. Access mode must be ``O_RDWR``.
|
Open flags. Access mode must be ``O_RDWR``.
|
||||||
|
|
||||||
When the ``O_NONBLOCK`` flag is given, the
|
When the ``O_NONBLOCK`` flag is given, the
|
||||||
:ref:`CEC_RECEIVE <CEC_RECEIVE>` and :ref:`CEC_DQEVENT <CEC_DQEVENT>` ioctls
|
:ref:`CEC_RECEIVE <CEC_RECEIVE>` and :c:func:`CEC_DQEVENT` ioctls
|
||||||
will return the ``EAGAIN`` error code when no message or event is available, and
|
will return the ``EAGAIN`` error code when no message or event is available, and
|
||||||
ioctls :ref:`CEC_TRANSMIT <CEC_TRANSMIT>`,
|
ioctls :ref:`CEC_TRANSMIT <CEC_TRANSMIT>`,
|
||||||
:ref:`CEC_ADAP_S_PHYS_ADDR <CEC_ADAP_S_PHYS_ADDR>` and
|
:ref:`CEC_ADAP_S_PHYS_ADDR <CEC_ADAP_S_PHYS_ADDR>` and
|
||||||
@@ -45,7 +46,9 @@ Arguments
|
|||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
To open a cec device applications call :c:func:`open()` with the
|
To open a cec device applications call :c:func:`open()` with the
|
||||||
|
@@ -20,16 +20,28 @@ Synopsis
|
|||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
|
||||||
.. cpp:function:: int poll( struct pollfd *ufds, unsigned int nfds, int timeout )
|
.. c:function:: int poll( struct pollfd *ufds, unsigned int nfds, int timeout )
|
||||||
|
:name: cec-poll
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
``ufds``
|
||||||
|
List of FD events to be watched
|
||||||
|
|
||||||
|
``nfds``
|
||||||
|
Number of FD efents at the \*ufds array
|
||||||
|
|
||||||
|
``timeout``
|
||||||
|
Timeout to wait for events
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
With the :c:func:`poll()` function applications can wait for CEC
|
With the :c:func:`poll()` function applications can wait for CEC
|
||||||
@@ -37,7 +49,7 @@ events.
|
|||||||
|
|
||||||
On success :c:func:`poll()` returns the number of file descriptors
|
On success :c:func:`poll()` returns the number of file descriptors
|
||||||
that have been selected (that is, file descriptors for which the
|
that have been selected (that is, file descriptors for which the
|
||||||
``revents`` field of the respective :c:type:`struct pollfd` structure
|
``revents`` field of the respective struct :c:type:`pollfd`
|
||||||
is non-zero). CEC devices set the ``POLLIN`` and ``POLLRDNORM`` flags in
|
is non-zero). CEC devices set the ``POLLIN`` and ``POLLRDNORM`` flags in
|
||||||
the ``revents`` field if there are messages in the receive queue. If the
|
the ``revents`` field if there are messages in the receive queue. If the
|
||||||
transmit queue has room for new messages, the ``POLLOUT`` and
|
transmit queue has room for new messages, the ``POLLOUT`` and
|
||||||
|
@@ -3,7 +3,9 @@
|
|||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
HDMI connectors provide a single pin for use by the Consumer Electronics
|
HDMI connectors provide a single pin for use by the Consumer Electronics
|
||||||
|
@@ -14,7 +14,8 @@ CEC_ADAP_G_CAPS - Query device capabilities
|
|||||||
Synopsis
|
Synopsis
|
||||||
========
|
========
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_caps *argp )
|
.. c:function:: int ioctl( int fd, CEC_ADAP_G_CAPS, struct cec_caps *argp )
|
||||||
|
:name: CEC_ADAP_G_CAPS
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
@@ -22,25 +23,25 @@ Arguments
|
|||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||||
|
|
||||||
``request``
|
|
||||||
CEC_ADAP_G_CAPS
|
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
All cec devices must support :ref:`ioctl CEC_ADAP_G_CAPS <CEC_ADAP_G_CAPS>`. To query
|
All cec devices must support :ref:`ioctl CEC_ADAP_G_CAPS <CEC_ADAP_G_CAPS>`. To query
|
||||||
device information, applications call the ioctl with a pointer to a
|
device information, applications call the ioctl with a pointer to a
|
||||||
struct :ref:`cec_caps <cec-caps>`. The driver fills the structure and
|
struct :c:type:`cec_caps`. The driver fills the structure and
|
||||||
returns the information to the application. The ioctl never fails.
|
returns the information to the application. The ioctl never fails.
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{1.2cm}|p{2.5cm}|p{13.8cm}|
|
||||||
|
|
||||||
.. _cec-caps:
|
.. c:type:: cec_caps
|
||||||
|
|
||||||
.. flat-table:: struct cec_caps
|
.. flat-table:: struct cec_caps
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
@@ -84,6 +85,7 @@ returns the information to the application. The ioctl never fails.
|
|||||||
macro.
|
macro.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}|
|
||||||
|
|
||||||
.. _cec-capabilities:
|
.. _cec-capabilities:
|
||||||
|
|
||||||
|
@@ -17,33 +17,35 @@ CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS - Get or set the logical addresses
|
|||||||
Synopsis
|
Synopsis
|
||||||
========
|
========
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_log_addrs *argp )
|
.. c:function:: int ioctl( int fd, CEC_ADAP_G_LOG_ADDRS, struct cec_log_addrs *argp )
|
||||||
|
:name: CEC_ADAP_G_LOG_ADDRS
|
||||||
|
|
||||||
|
.. c:function:: int ioctl( int fd, CEC_ADAP_S_LOG_ADDRS, struct cec_log_addrs *argp )
|
||||||
|
:name: CEC_ADAP_S_LOG_ADDRS
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||||
|
|
||||||
``request``
|
|
||||||
CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS
|
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
|
Pointer to struct :c:type:`cec_log_addrs`.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
To query the current CEC logical addresses, applications call
|
To query the current CEC logical addresses, applications call
|
||||||
:ref:`ioctl CEC_ADAP_G_LOG_ADDRS <CEC_ADAP_G_LOG_ADDRS>` with a pointer to a
|
:ref:`ioctl CEC_ADAP_G_LOG_ADDRS <CEC_ADAP_G_LOG_ADDRS>` with a pointer to a
|
||||||
:c:type:`struct cec_log_addrs` where the driver stores the logical addresses.
|
struct :c:type:`cec_log_addrs` where the driver stores the logical addresses.
|
||||||
|
|
||||||
To set new logical addresses, applications fill in
|
To set new logical addresses, applications fill in
|
||||||
:c:type:`struct cec_log_addrs` and call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
struct :c:type:`cec_log_addrs` and call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||||
with a pointer to this struct. The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
with a pointer to this struct. The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||||
is only available if ``CEC_CAP_LOG_ADDRS`` is set (the ``ENOTTY`` error code is
|
is only available if ``CEC_CAP_LOG_ADDRS`` is set (the ``ENOTTY`` error code is
|
||||||
returned otherwise). The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
returned otherwise). The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||||
@@ -64,8 +66,11 @@ logical addresses are claimed or cleared.
|
|||||||
Attempting to call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>` when
|
Attempting to call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>` when
|
||||||
logical address types are already defined will return with error ``EBUSY``.
|
logical address types are already defined will return with error ``EBUSY``.
|
||||||
|
|
||||||
|
.. c:type:: cec_log_addrs
|
||||||
|
|
||||||
.. _cec-log-addrs:
|
.. tabularcolumns:: |p{1.0cm}|p{7.5cm}|p{8.0cm}|
|
||||||
|
|
||||||
|
.. cssclass:: longtable
|
||||||
|
|
||||||
.. flat-table:: struct cec_log_addrs
|
.. flat-table:: struct cec_log_addrs
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
@@ -220,6 +225,8 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||||||
fallback to the Unregistered logical address. Note that if the Unregistered
|
fallback to the Unregistered logical address. Note that if the Unregistered
|
||||||
logical address was explicitly requested, then this flag has no effect.
|
logical address was explicitly requested, then this flag has no effect.
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||||
|
|
||||||
.. _cec-versions:
|
.. _cec-versions:
|
||||||
|
|
||||||
.. flat-table:: CEC Versions
|
.. flat-table:: CEC Versions
|
||||||
@@ -253,6 +260,7 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||||||
- CEC version according to the HDMI 2.0 standard.
|
- CEC version according to the HDMI 2.0 standard.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||||
|
|
||||||
.. _cec-prim-dev-types:
|
.. _cec-prim-dev-types:
|
||||||
|
|
||||||
@@ -319,6 +327,7 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||||||
- Use for a video processor device.
|
- Use for a video processor device.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||||
|
|
||||||
.. _cec-log-addr-types:
|
.. _cec-log-addr-types:
|
||||||
|
|
||||||
@@ -388,6 +397,8 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||||
|
|
||||||
.. _cec-all-dev-types-flags:
|
.. _cec-all-dev-types-flags:
|
||||||
|
|
||||||
.. flat-table:: CEC All Device Types Flags
|
.. flat-table:: CEC All Device Types Flags
|
||||||
|
@@ -17,24 +17,27 @@ CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR - Get or set the physical address
|
|||||||
Synopsis
|
Synopsis
|
||||||
========
|
========
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, __u16 *argp )
|
.. c:function:: int ioctl( int fd, CEC_ADAP_G_PHYS_ADDR, __u16 *argp )
|
||||||
|
:name: CEC_ADAP_G_PHYS_ADDR
|
||||||
|
|
||||||
|
.. c:function:: int ioctl( int fd, CEC_ADAP_S_PHYS_ADDR, __u16 *argp )
|
||||||
|
:name: CEC_ADAP_S_PHYS_ADDR
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||||
|
|
||||||
``request``
|
|
||||||
CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR
|
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
|
Pointer to the CEC address.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
To query the current physical address applications call
|
To query the current physical address applications call
|
||||||
|
@@ -15,7 +15,8 @@ CEC_DQEVENT - Dequeue a CEC event
|
|||||||
Synopsis
|
Synopsis
|
||||||
========
|
========
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_event *argp )
|
.. c:function:: int ioctl( int fd, CEC_DQEVENT, struct cec_event *argp )
|
||||||
|
:name: CEC_DQEVENT
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
@@ -23,20 +24,19 @@ Arguments
|
|||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||||
|
|
||||||
``request``
|
|
||||||
CEC_DQEVENT
|
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
CEC devices can send asynchronous events. These can be retrieved by
|
CEC devices can send asynchronous events. These can be retrieved by
|
||||||
calling :ref:`ioctl CEC_DQEVENT <CEC_DQEVENT>`. If the file descriptor is in
|
calling :c:func:`CEC_DQEVENT`. If the file descriptor is in
|
||||||
non-blocking mode and no event is pending, then it will return -1 and
|
non-blocking mode and no event is pending, then it will return -1 and
|
||||||
set errno to the ``EAGAIN`` error code.
|
set errno to the ``EAGAIN`` error code.
|
||||||
|
|
||||||
@@ -49,8 +49,9 @@ two :ref:`CEC_EVENT_STATE_CHANGE <CEC-EVENT-STATE-CHANGE>` events with
|
|||||||
the same state). In that case the intermediate state changes were lost but
|
the same state). In that case the intermediate state changes were lost but
|
||||||
it is guaranteed that the state did change in between the two events.
|
it is guaranteed that the state did change in between the two events.
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{1.2cm}|p{2.9cm}|p{13.4cm}|
|
||||||
|
|
||||||
.. _cec-event-state-change_s:
|
.. c:type:: cec_event_state_change
|
||||||
|
|
||||||
.. flat-table:: struct cec_event_state_change
|
.. flat-table:: struct cec_event_state_change
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
@@ -79,8 +80,9 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
has the unregistered logical address. In that case all other bits are 0.
|
has the unregistered logical address. In that case all other bits are 0.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:type:: cec_event_lost_msgs
|
||||||
|
|
||||||
.. _cec-event-lost-msgs_s:
|
.. tabularcolumns:: |p{1.0cm}|p{2.0cm}|p{14.5cm}|
|
||||||
|
|
||||||
.. flat-table:: struct cec_event_lost_msgs
|
.. flat-table:: struct cec_event_lost_msgs
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
@@ -105,8 +107,9 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
this is more than enough.
|
this is more than enough.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{1.0cm}|p{4.2cm}|p{2.5cm}|p{8.8cm}|
|
||||||
|
|
||||||
.. _cec-event:
|
.. c:type:: cec_event
|
||||||
|
|
||||||
.. flat-table:: struct cec_event
|
.. flat-table:: struct cec_event
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
@@ -120,11 +123,10 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
|
|
||||||
- ``ts``
|
- ``ts``
|
||||||
|
|
||||||
- Timestamp of the event in ns.
|
- :cspan:`1` Timestamp of the event in ns.
|
||||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
|
||||||
the same clock from userspace use :c:func:`clock_gettime(2)`.
|
|
||||||
|
|
||||||
-
|
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||||
|
the same clock from userspace use :c:func:`clock_gettime`.
|
||||||
|
|
||||||
- .. row 2
|
- .. row 2
|
||||||
|
|
||||||
@@ -132,9 +134,7 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
|
|
||||||
- ``event``
|
- ``event``
|
||||||
|
|
||||||
- The CEC event type, see :ref:`cec-events`.
|
- :cspan:`1` The CEC event type, see :ref:`cec-events`.
|
||||||
|
|
||||||
-
|
|
||||||
|
|
||||||
- .. row 3
|
- .. row 3
|
||||||
|
|
||||||
@@ -142,9 +142,7 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
|
|
||||||
- ``flags``
|
- ``flags``
|
||||||
|
|
||||||
- Event flags, see :ref:`cec-event-flags`.
|
- :cspan:`1` Event flags, see :ref:`cec-event-flags`.
|
||||||
|
|
||||||
-
|
|
||||||
|
|
||||||
- .. row 4
|
- .. row 4
|
||||||
|
|
||||||
@@ -176,6 +174,7 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
event.
|
event.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||||
|
|
||||||
.. _cec-events:
|
.. _cec-events:
|
||||||
|
|
||||||
@@ -205,6 +204,7 @@ it is guaranteed that the state did change in between the two events.
|
|||||||
application didn't dequeue CEC messages fast enough.
|
application didn't dequeue CEC messages fast enough.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.0cm}|p{0.6cm}|p{10.9cm}|
|
||||||
|
|
||||||
.. _cec-event-flags:
|
.. _cec-event-flags:
|
||||||
|
|
||||||
|
@@ -13,24 +13,27 @@ CEC_G_MODE, CEC_S_MODE - Get or set exclusive use of the CEC adapter
|
|||||||
Synopsis
|
Synopsis
|
||||||
========
|
========
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, __u32 *argp )
|
.. c:function:: int ioctl( int fd, CEC_G_MODE, __u32 *argp )
|
||||||
|
:name: CEC_G_MODE
|
||||||
|
|
||||||
|
.. c:function:: int ioctl( int fd, CEC_S_MODE, __u32 *argp )
|
||||||
|
:name: CEC_S_MODE
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||||
|
|
||||||
``request``
|
|
||||||
CEC_G_MODE, CEC_S_MODE
|
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
|
Pointer to CEC mode.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
By default any filehandle can use :ref:`CEC_TRANSMIT`, but in order to prevent
|
By default any filehandle can use :ref:`CEC_TRANSMIT`, but in order to prevent
|
||||||
@@ -71,6 +74,7 @@ always call :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>`.
|
|||||||
|
|
||||||
Available initiator modes are:
|
Available initiator modes are:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||||
|
|
||||||
.. _cec-mode-initiator_e:
|
.. _cec-mode-initiator_e:
|
||||||
|
|
||||||
@@ -114,6 +118,7 @@ Available initiator modes are:
|
|||||||
|
|
||||||
Available follower modes are:
|
Available follower modes are:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.6cm}|p{0.9cm}|p{10.0cm}|
|
||||||
|
|
||||||
.. _cec-mode-follower_e:
|
.. _cec-mode-follower_e:
|
||||||
|
|
||||||
@@ -206,6 +211,7 @@ Available follower modes are:
|
|||||||
|
|
||||||
Core message processing details:
|
Core message processing details:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.6cm}|p{10.9cm}|
|
||||||
|
|
||||||
.. _cec-core-processing:
|
.. _cec-core-processing:
|
||||||
|
|
||||||
|
@@ -16,28 +16,32 @@ CEC_RECEIVE, CEC_TRANSMIT - Receive or transmit a CEC message
|
|||||||
Synopsis
|
Synopsis
|
||||||
========
|
========
|
||||||
|
|
||||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_msg *argp )
|
.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg *argp )
|
||||||
|
:name: CEC_RECEIVE
|
||||||
|
|
||||||
|
.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg *argp )
|
||||||
|
:name: CEC_TRANSMIT
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
=========
|
=========
|
||||||
|
|
||||||
``fd``
|
``fd``
|
||||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||||
|
|
||||||
``request``
|
|
||||||
CEC_RECEIVE, CEC_TRANSMIT
|
|
||||||
|
|
||||||
``argp``
|
``argp``
|
||||||
|
Pointer to struct cec_msg.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
.. note::
|
||||||
|
|
||||||
|
This documents the proposed CEC API. This API is not yet finalized
|
||||||
and is currently only available as a staging kernel module.
|
and is currently only available as a staging kernel module.
|
||||||
|
|
||||||
To receive a CEC message the application has to fill in the
|
To receive a CEC message the application has to fill in the
|
||||||
``timeout`` field of :c:type:`struct cec_msg` and pass it to :ref:`ioctl CEC_RECEIVE <CEC_RECEIVE>`.
|
``timeout`` field of struct :c:type:`cec_msg` and pass it to
|
||||||
|
:ref:`ioctl CEC_RECEIVE <CEC_RECEIVE>`.
|
||||||
If the file descriptor is in non-blocking mode and there are no received
|
If the file descriptor is in non-blocking mode and there are no received
|
||||||
messages pending, then it will return -1 and set errno to the ``EAGAIN``
|
messages pending, then it will return -1 and set errno to the ``EAGAIN``
|
||||||
error code. If the file descriptor is in blocking mode and ``timeout``
|
error code. If the file descriptor is in blocking mode and ``timeout``
|
||||||
@@ -51,9 +55,9 @@ A received message can be:
|
|||||||
2. the result of an earlier non-blocking transmit (the ``sequence`` field will
|
2. the result of an earlier non-blocking transmit (the ``sequence`` field will
|
||||||
be non-zero).
|
be non-zero).
|
||||||
|
|
||||||
To send a CEC message the application has to fill in the
|
To send a CEC message the application has to fill in the struct
|
||||||
:c:type:`struct cec_msg` and pass it to
|
:c:type:` cec_msg` and pass it to :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>`.
|
||||||
:ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>`. The :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>` is only available if
|
The :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>` is only available if
|
||||||
``CEC_CAP_TRANSMIT`` is set. If there is no more room in the transmit
|
``CEC_CAP_TRANSMIT`` is set. If there is no more room in the transmit
|
||||||
queue, then it will return -1 and set errno to the ``EBUSY`` error code.
|
queue, then it will return -1 and set errno to the ``EBUSY`` error code.
|
||||||
The transmit queue has enough room for 18 messages (about 1 second worth
|
The transmit queue has enough room for 18 messages (about 1 second worth
|
||||||
@@ -71,7 +75,11 @@ checked against the received messages to find the corresponding transmit
|
|||||||
result.
|
result.
|
||||||
|
|
||||||
|
|
||||||
.. _cec-msg:
|
.. tabularcolumns:: |p{1.0cm}|p{3.5cm}|p{13.0cm}|
|
||||||
|
|
||||||
|
.. c:type:: cec_msg
|
||||||
|
|
||||||
|
.. cssclass:: longtable
|
||||||
|
|
||||||
.. flat-table:: struct cec_msg
|
.. flat-table:: struct cec_msg
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
@@ -87,7 +95,7 @@ result.
|
|||||||
|
|
||||||
- Timestamp in ns of when the last byte of the message was transmitted.
|
- Timestamp in ns of when the last byte of the message was transmitted.
|
||||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||||
the same clock from userspace use :c:func:`clock_gettime(2)`.
|
the same clock from userspace use :c:func:`clock_gettime`.
|
||||||
|
|
||||||
- .. row 2
|
- .. row 2
|
||||||
|
|
||||||
@@ -97,7 +105,7 @@ result.
|
|||||||
|
|
||||||
- Timestamp in ns of when the last byte of the message was received.
|
- Timestamp in ns of when the last byte of the message was received.
|
||||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||||
the same clock from userspace use :c:func:`clock_gettime(2)`.
|
the same clock from userspace use :c:func:`clock_gettime`.
|
||||||
|
|
||||||
- .. row 3
|
- .. row 3
|
||||||
|
|
||||||
@@ -247,6 +255,7 @@ result.
|
|||||||
valid if the :ref:`CEC_TX_STATUS_ERROR <CEC-TX-STATUS-ERROR>` status bit is set.
|
valid if the :ref:`CEC_TX_STATUS_ERROR <CEC-TX-STATUS-ERROR>` status bit is set.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||||
|
|
||||||
.. _cec-tx-status:
|
.. _cec-tx-status:
|
||||||
|
|
||||||
@@ -315,6 +324,7 @@ result.
|
|||||||
be set to explain which failures were seen.
|
be set to explain which failures were seen.
|
||||||
|
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||||
|
|
||||||
.. _cec-rx-status:
|
.. _cec-rx-status:
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_BILINGUAL_CHANNEL_SELECT
|
AUDIO_BILINGUAL_CHANNEL_SELECT
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t)
|
.. c:function:: int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct *audio_channel_select)
|
||||||
|
:name: AUDIO_BILINGUAL_CHANNEL_SELECT
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -25,20 +27,13 @@ Arguments
|
|||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
-
|
||||||
- .. row 1
|
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- audio_channel_select_t ch
|
- audio_channel_select_t ch
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_CHANNEL_SELECT
|
AUDIO_CHANNEL_SELECT
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_CHANNEL_SELECT, audio_channel_select_t)
|
.. c:function:: int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct *audio_channel_select)
|
||||||
|
:name: AUDIO_CHANNEL_SELECT
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -26,19 +28,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_CHANNEL_SELECT for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- audio_channel_select_t ch
|
- audio_channel_select_t ch
|
||||||
|
|
||||||
|
@@ -11,12 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_CLEAR_BUFFER
|
AUDIO_CLEAR_BUFFER
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_CLEAR_BUFFER)
|
.. c:function:: int ioctl(int fd, AUDIO_CLEAR_BUFFER)
|
||||||
|
:name: AUDIO_CLEAR_BUFFER
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -32,13 +33,6 @@ Arguments
|
|||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_CLEAR_BUFFER for this command.
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_CONTINUE
|
AUDIO_CONTINUE
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_CONTINUE)
|
.. c:function:: int ioctl(int fd, AUDIO_CONTINUE)
|
||||||
|
:name: AUDIO_CONTINUE
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -32,13 +34,6 @@ Arguments
|
|||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_CONTINUE for this command.
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
DVB audio close()
|
DVB audio close()
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int close(int fd)
|
.. c:function:: int close(int fd)
|
||||||
|
:name: dvb-audio-close
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
DVB audio open()
|
DVB audio open()
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int open(const char *deviceName, int flags)
|
.. c:function:: int open(const char *deviceName, int flags)
|
||||||
|
:name: dvb-audio-open
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -80,6 +82,8 @@ AUDIO_GET_STATUS. All other call will return with an error code.
|
|||||||
Return Value
|
Return Value
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
|
||||||
|
|
||||||
.. flat-table::
|
.. flat-table::
|
||||||
:header-rows: 0
|
:header-rows: 0
|
||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
DVB audio write()
|
DVB audio write()
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: size_t write(int fd, const void *buf, size_t count)
|
.. c:function:: size_t write(int fd, const void *buf, size_t count)
|
||||||
|
:name: dvb-audio-write
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_GET_CAPABILITIES
|
AUDIO_GET_CAPABILITIES
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_GET_CAPABILITIES, unsigned int *cap)
|
.. c:function:: int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)
|
||||||
|
:name: AUDIO_GET_CAPABILITIES
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -26,19 +28,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_GET_CAPABILITIES for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- unsigned int \*cap
|
- unsigned int \*cap
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_GET_PTS
|
AUDIO_GET_PTS
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_GET_PTS, __u64 *pts)
|
.. c:function:: int ioctl(int fd, AUDIO_GET_PTS, __u64 *pts)
|
||||||
|
:name: AUDIO_GET_PTS
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -26,19 +28,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_GET_PTS for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- __u64 \*pts
|
- __u64 \*pts
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_GET_STATUS
|
AUDIO_GET_STATUS
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_GET_STATUS, struct audio_status *status)
|
.. c:function:: int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)
|
||||||
|
:name: AUDIO_GET_STATUS
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -26,19 +28,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_GET_STATUS for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- struct audio_status \*status
|
- struct audio_status \*status
|
||||||
|
|
||||||
|
@@ -11,12 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_PAUSE
|
AUDIO_PAUSE
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_PAUSE)
|
.. c:function:: int ioctl(int fd, AUDIO_PAUSE)
|
||||||
|
:name: AUDIO_PAUSE
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -32,12 +33,6 @@ Arguments
|
|||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_PAUSE for this command.
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_PLAY
|
AUDIO_PLAY
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_PLAY)
|
.. c:function:: int ioctl(int fd, AUDIO_PLAY)
|
||||||
|
:name: AUDIO_PLAY
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -32,13 +34,6 @@ Arguments
|
|||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_PLAY for this command.
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_SELECT_SOURCE
|
AUDIO_SELECT_SOURCE
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SELECT_SOURCE, audio_stream_source_t source)
|
.. c:function:: int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)
|
||||||
|
:name: AUDIO_SELECT_SOURCE
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -26,19 +28,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_SELECT_SOURCE for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- audio_stream_source_t source
|
- audio_stream_source_t source
|
||||||
|
|
||||||
|
@@ -11,12 +11,14 @@ Name
|
|||||||
|
|
||||||
AUDIO_SET_ATTRIBUTES
|
AUDIO_SET_ATTRIBUTES
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(fd, int request = AUDIO_SET_ATTRIBUTES, audio_attributes_t attr )
|
.. c:function:: int ioctl(fd, AUDIO_SET_ATTRIBUTES, struct audio_attributes *attr )
|
||||||
|
:name: AUDIO_SET_ATTRIBUTES
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -26,19 +28,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_SET_ATTRIBUTES for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- audio_attributes_t attr
|
- audio_attributes_t attr
|
||||||
|
|
||||||
|
@@ -11,11 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_SET_AV_SYNC
|
AUDIO_SET_AV_SYNC
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SET_AV_SYNC, boolean state)
|
.. c:function:: int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)
|
||||||
|
:name: AUDIO_SET_AV_SYNC
|
||||||
|
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
@@ -26,33 +28,21 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_AV_SYNC for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- boolean state
|
- boolean state
|
||||||
|
|
||||||
- Tells the DVB subsystem if A/V synchronization shall be ON or OFF.
|
- Tells the DVB subsystem if A/V synchronization shall be ON or OFF.
|
||||||
|
|
||||||
- .. row 4
|
TRUE: AV-sync ON
|
||||||
|
|
||||||
-
|
FALSE: AV-sync OFF
|
||||||
- TRUE AV-sync ON
|
|
||||||
|
|
||||||
- .. row 5
|
|
||||||
|
|
||||||
-
|
|
||||||
- FALSE AV-sync OFF
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
|
@@ -11,12 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_SET_BYPASS_MODE
|
AUDIO_SET_BYPASS_MODE
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SET_BYPASS_MODE, boolean mode)
|
.. c:function:: int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)
|
||||||
|
:name: AUDIO_SET_BYPASS_MODE
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -26,34 +27,22 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_SET_BYPASS_MODE for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- boolean mode
|
- boolean mode
|
||||||
|
|
||||||
- Enables or disables the decoding of the current Audio stream in
|
- Enables or disables the decoding of the current Audio stream in
|
||||||
the DVB subsystem.
|
the DVB subsystem.
|
||||||
|
|
||||||
- .. row 4
|
TRUE: Bypass is disabled
|
||||||
|
|
||||||
-
|
FALSE: Bypass is enabled
|
||||||
- TRUE Bypass is disabled
|
|
||||||
|
|
||||||
- .. row 5
|
|
||||||
|
|
||||||
-
|
|
||||||
- FALSE Bypass is enabled
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
|
@@ -11,12 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_SET_EXT_ID
|
AUDIO_SET_EXT_ID
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(fd, int request = AUDIO_SET_EXT_ID, int id)
|
.. c:function:: int ioctl(fd, AUDIO_SET_EXT_ID, int id)
|
||||||
|
:name: AUDIO_SET_EXT_ID
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -26,19 +27,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_SET_EXT_ID for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- int id
|
- int id
|
||||||
|
|
||||||
|
@@ -11,12 +11,13 @@ Name
|
|||||||
|
|
||||||
AUDIO_SET_ID
|
AUDIO_SET_ID
|
||||||
|
|
||||||
|
.. attention:: This ioctl is deprecated
|
||||||
|
|
||||||
Synopsis
|
Synopsis
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SET_ID, int id)
|
.. c:function:: int ioctl(int fd, AUDIO_SET_ID, int id)
|
||||||
|
:name: AUDIO_SET_ID
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -26,19 +27,13 @@ Arguments
|
|||||||
:stub-columns: 0
|
:stub-columns: 0
|
||||||
|
|
||||||
|
|
||||||
- .. row 1
|
-
|
||||||
|
|
||||||
- int fd
|
- int fd
|
||||||
|
|
||||||
- File descriptor returned by a previous call to open().
|
- File descriptor returned by a previous call to open().
|
||||||
|
|
||||||
- .. row 2
|
-
|
||||||
|
|
||||||
- int request
|
|
||||||
|
|
||||||
- Equals AUDIO_SET_ID for this command.
|
|
||||||
|
|
||||||
- .. row 3
|
|
||||||
|
|
||||||
- int id
|
- int id
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user