One of the easiest ways to determine which modules are necessary is to
start with the kernel configuration that comes with your distribution's
kernel package. It is also much easier to determine which drivers are
needed on a running system, where the proper drivers are already bound to
the hardware.
If you do not already have a Linux distribution installed on the machine
that you are building the kernel for, use a LiveCD version of a
distribution. This allows you to boot Linux on the machine and determine
what kernel configuration options are needed in order to get the hardware
working properly.
Where Is the Kernel Configuration?
Almost all distributions provide the kernel configuration files as part of
the distribution kernel package. Read the distribution-specific
documentation for how to find these configurations. It is usually
somewhere below the /usr/src/linux/ directory tree.
If the kernel configuration is hard to find, look in the kernel itself.
Most distribution kernels are built to include the configuration within the
/proc filesystem. To determine if this is true for
your running kernel, enter:
$
ls /proc/config.gz
/proc/config.gz
If the /proc/config.gz filename is present, copy this
file to your kernel source directory and uncompress it:
$
cp /proc/config.gz ~/linux/
$
cd ~/linux
$
gzip -dv config.gz
config.gz: 74.9% -- replaced with config
Copy this configuration file into your kernel directory and rename it to
.config. Then use it as the basis of the kernel
configuration to build the kernel as described in
Chapter 5,
Configuring and Building
.
Using this configuration file should always generate a working kernel image
for your machine. The disadvantage of this kernel image is that you will
have built almost every kernel module and driver that is present in the
kernel source tree. This is almost never needed for a single machine, so
you can start to turn off different drivers and options that are not
needed. It is recommended that you disable only those options that you are sure
you do not need, as there might be parts of the system that rely on
specific options to be enabled.
Finding Which Module Is Needed
A configuration file that comes from a distribution takes a
very long time to build, because of all of the different drivers being built.
You want to build only the drivers for the hardware that you have, which
will save time on building the kernel, and allows you to build some or all
of the drivers into the kernel itself, possibly saving a bit of memory, and
on some architectures, making for a faster running system. To cut
your drivers down, you
need to determine which modules are needed to drive your hardware. We will
walk though two examples of how to find out what driver is needed to
control what piece of hardware.
Several locations on your system store useful information for determining which
devices are bound to which drivers in a running kernel. The most important
location is a virtual filesystem called sysfs.
sysfs should always be mounted at the
/sys location in your filesystem by the initialization
scripts of your Linux distribution. sysfs provides a
glimpse into how the different portions of the kernel are hooked together,
with many different symlinks pointing all around the filesystem.
In all of the following examples, real sysfs paths and
hardware types are shown. Your machine will be different, but the
relative locations of information will be the same. Do not be
alarmed if the file names in sysfs are
different from your machine; it is to be expected.
Additional, the internal structure of the sysfs filesystem
constantly changes around, due to the re-organization of devices and
rethinking by the kernel developers about how to best display
internal kernel structures to userspace. Because of this, over time, some of the symlinks
previously mentioned in this chapter might not be present. However the
information is all still there, just moved around a little bit.
Example: determining the network driver
One of the most common and important devices in the system is the network
interface card. It is imperative to figure out which driver is controlling
this device and enable it in your kernel configuration so that networking
works properly.
First, work backward from the network connection name to find out
which PCI device is controlling it. To do this, look at the different
network names:
$
ls /sys/class/net/
eth0 eth1 eth2 lo
The lo directory represents the network loopback device, and is not
attached to any real network device. The eth0,
eth1, and eth2 directories are what you should
pay attention to, as they represent real network devices.
To look further at these network devices in order to figure out which you care
about, use the ifconfig utility:
$
/sbin/ifconfig -a
eth0 Link encap:Ethernet HWaddr 00:12:3F:65:7D:C2
inet addr:192.168.0.13 Bcast:192.168.0.255 Mask:255.255.255.0
UP BROADCAST NOTRAILERS RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2720792 errors:0 dropped:0 overruns:0 frame:0
TX packets:1815488 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:3103826486 (2960.0 Mb) TX bytes:371424066 (354.2 Mb)
Base address:0xdcc0 Memory:dfee0000-dff00000
eth1 Link encap:UNSPEC HWaddr 80-65-00-12-7D-C2-3F-00-00-00-00-00-00-00-00-00
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
eth2 Link encap:UNSPEC HWaddr 00-02-3C-04-11-09-D2-BA-00-00-00-00-00-00-00-00
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:60 errors:0 dropped:0 overruns:0 frame:0
TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:13409 (13.0 Kb) TX bytes:13409 (13.0 Kb)
From this list, you can tell that the eth0 device is the network device
that is active and working, as can be seen by the lines:
eth0 Link encap:Ethernet HWaddr 00:12:3F:65:7D:C2
inet addr:192.168.0.13 Bcast:192.168.0.255 Mask:255.255.255.0
These show this is an Ethernet device with valid IP (inet) address assigned
to it.
Now that we have determined that we want to make sure the
eth0 device will be working in our new kernel, we need
to find which driver is controlling it. This is simply a matter of walking
the different links in the sysfs filesystem, which can
be done in a one-line command:
$
basename `readlink /sys/class/net/eth0/device/driver/module`
e1000
This shows that the module named e1000 is controlling
the eth0 network device.
The
basename...
command shown compresses the following
steps into a single command line:
-
Follow the /sys/class/net/eth0/device symlink into the
directory within the /sys/device/ tree that contains
the information for the device that controls eth0.
Note that the /sys/class/net/eth0 directory might also
be a symlink on the newer versions of the kernel.
-
Within the directory that describes the device in sysfs,
there is a symlink to the driver bound to this device. That
symlink is called driver, so we follow that link.
-
Within the directory that describes the driver in sysfs,
there is a symlink to the module that this driver is contained within.
That symlink is called module. We want the target of
that symlink. To get the target, we use the
readlink
command, which produces output such as:
$
readlink /sys/class/net/eth0/device/driver/module
../../../../module/e1000
-
As we care only about the name of the module, we want to strip the rest of
the path off the output of the
readlink
command, and
only save the rightmost portion. That is what the
basename
command does. Executed directly on a
pathname, it would produce:
$
basename ../../../../module/e1000
e1000
So we put the output of the long symlink traversal to the
readlink
location into the
basename
program, enabling the whole process to be done in one line.
Now that we have the module name, we need to find the kernel configuration
option that controls it. You can look through the different network
device configuration menus or search the kernel source code itself
to make sure you have the right option:
$
cd ~/linux/linux-2.6.17.8
$
find -type f -name Makefile | xargs grep e1000
./drivers/net/Makefile:obj-$(CONFIG_E1000) += e1000/
./drivers/net/e1000/Makefile:obj-$(CONFIG_E1000) += e1000.o
./drivers/net/e1000/Makefile:e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
Remember to replace the e1000 used for this example with the name of the module
that you are looking to find.
The important thing to look for in the output of the previous
find
command is
any line that has the term CONFIG_ in it. That is the
configuration option that the kernel needs to have enabled in order to
build the module. In the above example, the option
CONFIG_E1000 is the configuration option that you are
looking for.
Now you have the information you need to configure the kernel. Run the
menu configuration tool:
$
make menuconfig
Then press the / key (which initiates a search) and type in the configuration
option, minus the CONFIG_ portion of the
string. This process is shown in Figure 8.1, “Searching in menuconfig”.
The kernel configuration system will then tell you exactly where
to select the option to enable this module. See Figure 8.2, “Result of searching in menuconfig”.
The first item in the display exactly matches what you
searched for. The location information in the display tells you that to build the module e1000 into the,
kernel the following configuration option must be enabled:
Device Drivers
Network device support
[*] Network device support
Ethernet (1000 Mbit)
[*] Intel(R) PRO/1000 Gigabit Ethernet support
These steps will work for any type of device active in the kernel.
As
another example, let us look at a USB-to-serial converter that is present
in our example system. It is currently connected to the
/dev/ttyUSB0 port, so you need to look in the
sysfs tty section:
$
ls /sys/class/tty/ | grep USB
ttyUSB0
You can trace through sysfs for this device to find
the controlling module, as shown in the previous section:
$
basename `readlink /sys/class/tty/ttyUSB0/device/driver/module`
pl2303
Then search the kernel source tree to find the configuration option that you
need to enable:
$
cd ~/linux/linux-2.6.17.8
$
find -type f -name Makefile | xargs grep pl2303
./drivers/usb/serial/Makefile:obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
Use the kernel configuration tool, as shown in Figure 8.3, “Searching for USB_SERIAL_PL2303”, to find the proper option to enable
in order to set the CONFIG_USB_SERIAL_PL2303 option.
In our case, this displays the screen shown in Figure 8.4, “Result of searching for USB_SERIAL_PL2303”.
This shows exactly where to find the USB Prolific 2303 Single Port
Serial Driver option that is needed to control this device
properly.
Summary of device discovery
In summary, here are the steps needed to find the driver for a device that
has a working driver already bound to it:
-
Find the proper sysfs class device that the device is
bound to. Network devices are listed in
/sys/class/net and tty devices in
/sys/class/tty. Other types of devices are listed in
other directories in /sys/class, depending on the type of
device.
-
Trace through the sysfs tree to find the module name
that controls this device. It will be found in the
/sys/class/
class_name/device_name
/device/driver/module, and can be
displayed using the
readlink
and
basename
applications:
$
basename `readlink /sys/class/
class_name/device_name
/device/driver/module`
-
Search the kernel Makefiles for the CONFIG_ rule that
builds this module name by using
find
and
grep
:
$
find -type f -name Makefile | xargs grep
module_name
-
Search in the kernel configuration system for that configuration value and
go to the location in the menu that it specifies to enable that driver to
be built.
Let the kernel tell us what we need
Now that we have gone through all of the steps of poking around in
sysfs and following symlinks to module names, here is a
very simple script that will do all of that work, in a different way:
#!/bin/bash
#
# find_all_modules.sh
#
for i in `find /sys/ -name modalias -exec cat {} \;`; do
/sbin/modprobe --config /dev/null --show-depends $i ;
done | rev | cut -f 1 -d '/' | rev | sort -u
This script goes through sysfs and finds all files
called modalias. The modalias
file contains the module alias that tells the
modprobe
command which module should be loaded to
control this device. The module alias is made up of a combination of
device manufacturer, ID, class type, and other unique identifiers for that
specific type of device. All kernel driver modules have an internal list
of devices that they support that is generated automatically by the list of
devices the driver tells the kernel it supports. The
modprobe
looks through this list of devices by all
drivers and tries to match it up with the alias it has. If it finds a
match, it will then load the module (this procedure is how the automatic
driver loading functionalty in Linux works.)
The script has the
modprobe
program stop before actually
loading the module, and just print out what actions it would take. This
gives us a list of all of the modules that are needed to control all
devices in the system. A little cleaning up of the list, by sorting it and
finding the proper field to display, results in this output:
$
find_all_modules.sh
8139cp.ko
8139too.ko
ehci-hcd.ko
firmware_class.ko
i2c-i801.ko
ieee80211.ko
ieee80211_crypt.ko
ipw2200.ko
mii.ko
mmc_core.ko
pcmcia_core.ko
rsrc_nonstatic.ko
sdhci.ko
snd-hda-codec.ko
snd-hda-intel.ko
snd-page-alloc.ko
snd-pcm.ko
snd-timer.ko
snd.ko
soundcore.ko
uhci-hcd.ko
usbcore.ko
yenta_socket.ko
This is a list of all of the modules that are needed to control the
hardware in the machine.
The script will also probably print out some error messages that look like:
FATAL: Module pci:v00008086d00002592sv000010CFsd000012E2bc03sc00i00 not found.
FATAL: Module serio:ty01pr00id00ex00 not found.
Which means that it could not find a module that can control that device.
Do not be concerned about this, as some devices do not have kernel drivers
that will work for them.