-
Notifications
You must be signed in to change notification settings - Fork 7
/
ch07.xml
1355 lines (1211 loc) · 46.5 KB
/
ch07.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<chapter id="LKN-custom">
<title>
Customizing a Kernel
</title>
<para>
One of the hardest parts of building your own version of the Linux kernel
is determining exactly which drivers and configuration options are needed
for your machine to work properly. This chapter will walk you
through this process of finding and selecting the correct drivers.
</para>
<sect1>
<title>Using a Distribution Kernel</title>
<para>
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
<!--
AO: I hope I did not change the sense of this paragraph.
gkh: nope, looks good to me.
-->
the hardware.
</para>
<para>
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.
</para>
<sect2>
<title>Where Is the Kernel Configuration?</title>
<para>
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 <filename>/usr/src/linux/</filename> directory tree.
</para>
<para>
If the kernel configuration is hard to find, look in the kernel itself.
Most distribution kernels are built to include the configuration within the
<filename>/proc</filename> filesystem. To determine if this is true for
your running kernel, enter:
<screen>
$ <userinput>ls /proc/config.gz</userinput>
/proc/config.gz
</screen>
If the <filename>/proc/config.gz</filename> filename is present, copy this
file to your kernel source directory and uncompress it:
<screen>
$ <userinput>cp /proc/config.gz ~/linux/</userinput>
$ <userinput>cd ~/linux</userinput>
$ <userinput>gzip -dv config.gz</userinput>
config.gz: 74.9% -- replaced with config
</screen>
Copy this configuration file into your kernel directory and rename it to
<filename>.config</filename>. Then use it as the basis of the kernel
configuration to build the kernel as described in
<xref linkend="LKN-chapter-building" />.
</para>
<para>
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.
</para>
</sect2>
<sect2>
<title>Finding Which Module Is Needed</title>
<para>
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.
</para>
<para>
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 <literal>sysfs</literal>.
<literal>sysfs</literal> should always be mounted at the
<filename>/sys</filename> location in your filesystem by the initialization
scripts of your Linux distribution. <literal>sysfs</literal> provides a
glimpse into how the different portions of the kernel are hooked together,
with many different symlinks pointing all around the filesystem.
</para>
<para>
In all of the following examples, real <literal>sysfs</literal> 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 <literal>sysfs</literal> are
different from your machine; it is to be expected.
</para>
<!--
AO: The following is fairly general, so I moved it up in the chapter.
gkh: that's fine.
-->
<para>
Additional, the internal structure of the <literal>sysfs</literal> 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.
</para>
<sect3>
<title>Example: determining the network driver</title>
<para>
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.
</para>
<para>
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:
<screen>
$ <userinput>ls /sys/class/net/</userinput>
eth0 eth1 eth2 lo
</screen>
The <literal>lo</literal> directory represents the network loopback device, and is not
attached to any real network device. The <literal>eth0</literal>,
<literal>eth1</literal>, and <literal>eth2</literal> directories are what you should
pay attention to, as they represent real network devices.
</para>
<para>
To look further at these network devices in order to figure out which you care
about, use the <literal>ifconfig</literal> utility:
<screen>
$ <userinput>/sbin/ifconfig -a</userinput>
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)
</screen>
From this list, you can tell that the <literal>eth0</literal> device is the network device
that is active and working, as can be seen by the lines:
<screen>
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
</screen>
These show this is an Ethernet device with valid IP (<literal>inet</literal>) address assigned
to it.
</para>
<para>
Now that we have determined that we want to make sure the
<literal>eth0</literal> 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 <literal>sysfs</literal> filesystem, which can
be done in a one-line command:
<screen>
$ <userinput>basename `readlink /sys/class/net/eth0/device/driver/module`</userinput>
e1000
</screen>
This shows that the module named <literal>e1000</literal> is controlling
the <literal>eth0</literal> network device.
The <command>basename...</command> command shown compresses the following
steps into a single command line:
<orderedlist>
<listitem>
<para>
Follow the <filename>/sys/class/net/eth0/device</filename> symlink into the
directory within the <filename>/sys/device/</filename> tree that contains
the information for the device that controls <literal>eth0</literal>.
Note that the <filename>/sys/class/net/eth0</filename> directory might also
be a symlink on the newer versions of the kernel.
</para>
</listitem>
<listitem>
<para>
Within the directory that describes the device in <literal>sysfs</literal>,
there is a symlink to the driver bound to this device. That
symlink is called <filename>driver</filename>, so we follow that link.
</para>
</listitem>
<listitem>
<para>
Within the directory that describes the driver in <literal>sysfs</literal>,
there is a symlink to the module that this driver is contained within.
That symlink is called <filename>module</filename>. We want the target of
that symlink. To get the target, we use the <command>readlink</command>
command, which produces output such as:
<screen>
$ <userinput>readlink /sys/class/net/eth0/device/driver/module</userinput>
../../../../module/e1000
</screen>
</para>
</listitem>
<listitem>
<para>
As we care only about the name of the module, we want to strip the rest of
the path off the output of the <command>readlink</command> command, and
only save the rightmost portion. That is what the
<command>basename</command> command does. Executed directly on a
pathname, it would produce:
<screen>
$ <userinput>basename ../../../../module/e1000</userinput>
e1000
</screen>
</para>
</listitem>
</orderedlist>
So we put the output of the long symlink traversal to the
<command>readlink</command> location into the <command>basename</command>
program, enabling the whole process to be done in one line.
</para>
<para>
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:
<screen>
$ <userinput>cd ~/linux/linux-2.6.17.8</userinput>
$ <userinput>find -type f -name Makefile | xargs grep e1000</userinput>
./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
</screen>
Remember to replace the <literal>e1000</literal> used for this example with the name of the module
that you are looking to find.
</para>
<para>
The important thing to look for in the output of the previous <command>find</command> command is
any line that has the term <literal>CONFIG_</literal> 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
<literal>CONFIG_E1000</literal> is the configuration option that you are
looking for.
</para>
<para>
Now you have the information you need to configure the kernel. Run the
menu configuration tool:
<screen>
$ <userinput>make menuconfig</userinput>
</screen>
Then press the <literal>/</literal> key (which initiates a search) and type in the configuration
option, minus the <literal>CONFIG_</literal> portion of the
string. This process is shown in <xref linkend="config_search" />.
</para>
<figure id="config_search">
<title>Searching in menuconfig</title>
<graphic fileref="images/config_search.png" scalefit="1"/>
</figure>
<para>
The kernel configuration system will then tell you exactly where
to select the option to enable this module. See <xref linkend="config_search_found" />.
</para>
<figure id="config_search_found">
<title>Result of searching in menuconfig</title>
<graphic fileref="images/config_search_found.png" scalefit="1"/>
</figure>
<para>
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 <literal>e1000</literal> into the,
kernel the following configuration option must be enabled:
<screen>
Device Drivers
Network device support
[*] Network device support
Ethernet (1000 Mbit)
[*] Intel(R) PRO/1000 Gigabit Ethernet support
</screen>
</para>
<para>
These steps will work for any type of device active in the kernel.
</para>
</sect3>
<sect3>
<title>Example: a USB device</title>
<para>
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
<literal>/dev/ttyUSB0</literal> port, so you need to look in the
<literal>sysfs</literal> tty section:
<screen>
$ <userinput>ls /sys/class/tty/ | grep USB</userinput>
ttyUSB0
</screen>
You can trace through <literal>sysfs</literal> for this device to find
the controlling module, as shown in the previous section:
<screen>
$ <userinput>basename `readlink /sys/class/tty/ttyUSB0/device/driver/module`</userinput>
pl2303
</screen>
Then search the kernel source tree to find the configuration option that you
need to enable:
<screen>
$ <userinput>cd ~/linux/linux-2.6.17.8</userinput>
$ <userinput>find -type f -name Makefile | xargs grep pl2303</userinput>
./drivers/usb/serial/Makefile:obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
</screen>
Use the kernel configuration tool, as shown in <xref
linkend="config_search_pl2303" />, to find the proper option to enable
in order to set the <literal>CONFIG_USB_SERIAL_PL2303</literal> option.
<figure id="config_search_pl2303">
<title>Searching for <literal>USB_SERIAL_PL2303</literal></title>
<graphic fileref="images/config_search_pl2303.png" scalefit="1"/>
</figure>
In our case, this displays the screen shown in <xref
linkend="config_search_pl2303_found" />.
<figure id="config_search_pl2303_found">
<title>Result of searching for <literal>USB_SERIAL_PL2303</literal></title>
<graphic fileref="images/config_search_pl2303_found.png" scalefit="1"/>
</figure>
This shows exactly where to find the <literal>USB Prolific 2303 Single Port
Serial Driver</literal> option that is needed to control this device
properly.
</para>
</sect3>
<sect3>
<title>Summary of device discovery</title>
<para>
In summary, here are the steps needed to find the driver for a device that
has a working driver already bound to it:
<orderedlist>
<listitem>
<para>
Find the proper <literal>sysfs</literal> class device that the device is
bound to. Network devices are listed in
<filename>/sys/class/net</filename> and tty devices in
<filename>/sys/class/tty</filename>. Other types of devices are listed in
other directories in <literal>/sys/class</literal>, depending on the type of
device.
</para>
</listitem>
<listitem>
<para>
Trace through the <literal>sysfs</literal> tree to find the module name
that controls this device. It will be found in the
<filename>/sys/class/</filename><replaceable>class_name/device_name</replaceable><filename>/device/driver/module</filename>, and can be
displayed using the <command>readlink</command> and
<command>basename</command> applications:
<screen>
$ <userinput>basename `readlink /sys/class/<replaceable>class_name/device_name</replaceable>/device/driver/module`</userinput>
</screen>
</para>
</listitem>
<listitem>
<para>
Search the kernel Makefiles for the <literal>CONFIG_</literal> rule that
builds this module name by using <command>find</command> and
<command>grep</command>:
<screen>
$ <userinput>find -type f -name Makefile | xargs grep <replaceable>module_name</replaceable></userinput>
</screen>
</para>
</listitem>
<listitem>
<para>
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.
</para>
</listitem>
</orderedlist>
</para>
</sect3>
<sect3>
<title>Let the kernel tell us what we need</title>
<!--
AO: Why shouldn't this come first, before the manual method? You
should supply a reason for using the manual method, even if the
reason is just educational.
gkh: Hm, it is educational, and the information produced below doesn't
give you everything you need, you still need to follow the steps learned
above to do something with the information (figure out based on the
module name, what config option to enable.)
-->
<para>
Now that we have gone through all of the steps of poking around in
<literal>sysfs</literal> and following symlinks to module names, here is a
very simple script that will do all of that work, in a different way:
<screen>
#!/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
</screen>
This script goes through <literal>sysfs</literal> and finds all files
called <filename>modalias</filename>. The <filename>modalias</filename>
file contains the module alias that tells the
<command>modprobe</command> 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
<command>modprobe</command> 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.)
</para>
<para>
The script has the <command>modprobe</command> 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:
<screen>
$ <userinput>find_all_modules.sh</userinput>
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
</screen>
This is a list of all of the modules that are needed to control the
hardware in the machine.
</para>
<para>
The script will also probably print out some error messages that look like:
<screen>
FATAL: Module pci:v00008086d00002592sv000010CFsd000012E2bc03sc00i00 not found.
FATAL: Module serio:ty01pr00id00ex00 not found.
</screen>
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.
</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Determining the Correct Module From Scratch</title>
<para>
Sometimes you do not have the option of getting a distribution kernel
working on a machine in order to determine what kernel modules are needed to
drive the hardware. Or you have added new hardware to your system, and you
need to figure out what kernel configuration option needs to be enabled to
get it to work properly. This section will help you determine how to find
that configuration option to get the hardware up and running.
</para>
<para>
The easiest way to figure out which driver controls a new device is to
build all of the different drivers of that type in the kernel source tree
as modules, and let the <literal>udev</literal> startup process match
the driver to the device. Once this happens, you should be able
to work backwards using the steps just discussed to determine the proper
driver needed, and then go back and enable just that driver in the kernel
configuration.
</para>
<para>
But if you do not want to build all drivers, or this does not work for some
reason, it will require a bit more work to determine the proper
driver that is needed. The following steps are complex and require digging in
the kernel source code at times. Do not be afraid of this, it will only
help you understand your hardware and the kernel source better.
</para>
<para>
The steps involved in matching the driver to the device differ
depending on the type of device that you are working with. We will discuss
the two most common forms of devices in this chapter: PCI and USB devices. The
methods described here will also work with other types of devices.
</para>
<para>
Also, it is very important for the kernel to be able to find all of the
filesystems in the system, the most important one being the root
filesystem. We will go into how to do this toward the end of the
chapter in <xref linkend="LKN-custom_rootfs" />.
</para>
<sect2>
<title>PCI devices</title>
<para>
PCI devices are distinguished by vendor ID and device ID; each
combination of vendor and device ID could require a unique
driver. This is the basis for the research this section shows you how
to do.
</para>
<para>
For this example, let us use a PCI network card that is not working with
the currently running kernel version. This example will be different from
your situation, with different PCI device and bus ID values, but the steps
involved should be relevant to any type of PCI device you wish to find a
working driver for.
</para>
<para>
First, find the PCI device in the system that is not working. To
get a list of all PCI devices, use the <command>lspci</command> program.
Because we care only about Ethernet PCI devices, we will narrow our
search of the PCI devices by searching only for strings containing the term
<literal>Ethernet</literal> (case-insensitive):
<screen>
$ <userinput>/usr/sbin/lspci | grep -i ethernet </userinput>
06:04.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (rev 10)
</screen>
This is the device we wish to get working.
<footnote>
<para>
Note that you can just try searching through the kernel configuration for a
device that matches the string described here, a device from Realtek
Semiconductor with a product name of
<literal>RTL-8139/8139C/8139C+</literal>, but this does not always
work. That is why we are taking the long way around in this chapter.
</para>
</footnote>
</para><note>
<para>
Almost all distributions place the <command>lspci</command> program in the
<filename>/usr/sbin/</filename> directory, but some place it in other
locations. To find out where it is located, enter:
<screen>
$ <userinput>which lspci</userinput>
/usr/sbin/lspci
</screen>
If you are using a distribution that puts it somewhere else,
please use that path whenever we discuss using <command>lspci</command>
</para>
</note>
<para>
The first few bits of the <command>lspci</command> output show the PCI bus
id for this device, <literal>06:04.0</literal>. That is the value we will
use when looking through <literal>sysfs</literal> in order to find out more
information about this device.
</para>
<para>
Go into <literal>sysfs</literal> where all of the different PCI devices are
listed, and look at their names:
<screen>
$ <userinput>cd /sys/bus/pci/devices/</userinput>
$ <userinput>ls</userinput>
0000:00:00.0 0000:00:1d.0 0000:00:1e.0 0000:00:1f.3 0000:06:03.3
0000:00:02.0 0000:00:1d.1 0000:00:1f.0 0000:06:03.0 0000:06:03.4
0000:00:02.1 0000:00:1d.2 0000:00:1f.1 0000:06:03.1 0000:06:04.0
0000:00:1b.0 0000:00:1d.7 0000:00:1f.2 0000:06:03.2 0000:06:05.0
</screen>
The kernel numbers PCI devices with a leading <literal>0000:</literal> that
does not show up in the output of the <command>lspci</command> program.
<footnote>
<para>
Some 64bit processors will show the leading bus number for PCI devices in
the output of <command>lspci</command>, but for the majority of the common
Linux machines, it will not show up by default.
</para>
</footnote>
So add the leading <literal>0000:</literal> onto the number that you found
using <literal>lspci</literal> and go into that directory:
<screen>
$ <userinput>cd 0000:06:04.0</userinput>
</screen>
In this directory, you want to know the values of the
<filename>vendor</filename> and <filename>device</filename> filenames:
<screen>
$ <userinput>cat vendor</userinput>
0x10ec
$ <userinput>cat device</userinput>
0x8139
</screen>
These are the vendor and device IDs for this PCI device. The kernel uses
these values to match a driver to a device properly. PCI drivers tell the
kernel which vendor and device IDs they will support so that the
kernel knows how to bind the driver to the proper device. Write them down
somewhere, as we will refer to them later.
</para>
<para>
Now that we know the vendor and product ID for this PCI device, we need to
find the proper kernel driver that advertises that it supports this device.
Go back to the kernel source directory:
<screen>
$ <userinput>cd ~/linux/linux-2.6.17.8/</userinput>
</screen>
The monst common location for PCI IDs in the kernel
source tree is <filename>include/linux/pci_ids.h</filename>.
Search that file for our vendor product number:
<screen>
$ <userinput>grep -i 0x10ec include/linux/pci_ids.h</userinput>
#define PCI_VENDOR_ID_REALTEK 0x10ec
</screen>
The defined value here, <literal>PCI_VENDOR_ID_REALTEK</literal> is what
will probably be used in any kernel driver that purports to support devices
from this manufacturer.
</para>
<para>
To be safe, also look in this file for our device ID, as it is also sometimes
described there:
<screen>
$ <userinput>grep -i 0x8139 include/linux/pci_ids.h</userinput>
#define PCI_DEVICE_ID_REALTEK_8139 0x8139
</screen>
That definition will be useful later.
</para>
<para>
Now look for driver source files referring to this vendor definition:
<screen>
$ <userinput>grep -Rl PCI_VENDOR_ID_REALTEK *</userinput>
include/linux/pci_ids.h
drivers/net/r8169.c
drivers/net/8139too.c
drivers/net/8139cp.c
</screen>
The first file listed here, <filename>pci_ids.h</filename> does not need to
be looked at, as that is where we found the original definition.
But the files <filename>r8139.c</filename>,
<filename>8139too.c</filename>, and <filename>8169cp.c</filename> in the
<filename>drivers/net/</filename> subdirectory should be examined more
closely.
</para>
<para>
Open one of these files in an editor and search for
<literal>PCI_VENDOR_ID_REALTEK</literal>. In the file
<filename>drivers/net/r8169.c</filename>, it shows up in this section of
code:
<programlisting>
static struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), },
{ PCI_DEVICE(0x16ec, 0x0116), },
{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, },
{0,},
};
</programlisting>
All PCI drivers contain a list of the different devices that they support.
That list is contained in a structure of
<literal>struct pci_device_id</literal> values, just like this one. That
is what we need to look at in order to determine whether our device is supported
by this driver. The vendor value matches here, but the second value after
the vendor is the device value. Our device has the value
<literal>0x8139</literal>, while this driver supports the device values of
<literal>0x8169</literal> and <literal>0x8129</literal> for devices with
the vendor ID of <literal>PCI_VENDOR_ID_REALTEK</literal>. So this driver
will not support our device.
</para>
<para>
Moving on to the next file <filename>drivers/net/8139too.c</filename>, we
find the string <literal>PCI_VENDOR_ID_REALTEK</literal> in the
following bit of code:
<programlisting>
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
dev_info(&pdev->dev,
"This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
pdev->vendor, pdev->device, pci_rev);
dev_info(&pdev->dev,
"Use the \"8139cp\" driver for improved performance and stability.\n");
}
</programlisting>
The use of the <literal>PCI_VENDOR_ID_REALTEK</literal> value here also
corresponds with the code that checks whether the PCI device id matches the
<literal>PCI_DEVICE_ID_REALTEK_8139</literal> value. If it does, the
driver is to print out a message that says:
<quote>
Use the 8139cp driver for improved performance and stability.
</quote>
Perhaps we should look at that driver next. Even if we did not have such a
visible clue, the <filename>8139too.c</filename> driver does not have the vendor and device ID pair that
we are looking for in a <literal>struct pci_device_id</literal> variable,
so that gives us the clue that it will not support our device.
</para>
<para>
Finally, look at the <filename>drivers/net/8139cp.c</filename> file. It
uses the <literal>PCI_VENDOR_ID_REALTEK</literal> definition in the
following code segment:
<programlisting>
static struct pci_device_id cp_pci_tbl[] = {
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
{ PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
{ },
};
MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
</programlisting>
Here is a use of both our vendor and device ID values in a <literal>struct
pci_device_id</literal> variable. This driver should support our device.
</para>
<para>
Now that we have the driver name, we can work backward, as shown in the
first section in this chapter to find the proper kernel configuration value
that should be enabled to build this driver.
</para>
<para>
In summary, here are the steps needed in order to find which PCI driver
can control a specific PCI device:
<orderedlist>
<listitem>
<para>
Find the PCI bus ID of the device for which you want to find the driver, using
<command>lspci</command>.
</para>
</listitem>
<listitem>
<para>
Go into the <filename>/sys/bus/pci/devices/0000:</filename><replaceable>bus_id</replaceable> directory,
where <replaceable>bus_id</replaceable> is the PCI bus ID found in the previous
step.
</para>
</listitem>
<listitem>
<para>
Read the values of the <filename>vendor</filename> and
<filename>device</filename> files in the PCI device directory.
</para>
</listitem>
<listitem>
<para>
Move back to the kernel source tree and look in
<filename>include/linux/pci_ids.h</filename> for the PCI vendor and device
IDs found in the previous step.
</para>
</listitem>
<listitem>
<para>
Search the kernel source tree for references to those values in drivers. Both
the vendor and device ID should be in a
<literal>struct pci_device_id</literal> definition.
</para>
</listitem>
<listitem>
<para>
Search the kernel Makefiles for the <literal>CONFIG_</literal> rule that
builds this driver by using <command>find</command> and
<command>grep</command>:
<screen>
$ <userinput>find -type f -name Makefile | xargs grep DRIVER_NAME</userinput>
</screen>
</para>
</listitem>
<listitem>
<para>
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.
</para>
</listitem>
</orderedlist>
</para>
</sect2>
<sect2>
<title>USB devices</title>
<para>
Finding the specific driver for a USB device is much like finding the
driver for a PCI device as described in the previous section, with only
minor differences in finding the bus ID values.
</para>
<para>
In this example, let us find the driver that is needed for a USB wireless
device. As with the PCI device example, the details in this example will
be different from your situation, but the steps involved should be relevant
to any type of USB device for which you wish to find a working driver.
</para>
<para>
As with the PCI device, the bus ID must be found for the USB device you
wish to find the driver for. To do this, you can use the
<command>lsusb</command> program that comes in the
<literal>usbutils</literal> package.
</para>
<para>
The <command>lsusb</command> program shows all USB devices attached to
the system. As willou do not know what the specific device your are looking for
is called, start by looking at all devices:
<screen>
$ <userinput>/usr/sbin/lsusb</userinput>
Bus 002 Device 003: ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 002 Device 001: ID 0000:0000
Bus 005 Device 003: ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 005 Device 001: ID 0000:0000
Bus 004 Device 003: ID 157e:300d
Bus 004 Device 002: ID 045e:001c Microsoft Corp.
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000
</screen>
The devices with an ID of <literal>0000:0000</literal> can be ignored, as
they are USB host controllers that drive the bus itself. Filtering
them away leaves us with four devices:
<screen>
$ <userinput>/usr/sbin/lsusb | grep -v 0000:0000</userinput>
Bus 002 Device 003: ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 005 Device 003: ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 004 Device 003: ID 157e:300d
Bus 004 Device 002: ID 045e:001c Microsoft Corp.
</screen>
Because USB devices are easy to remove, unplug the device you want to find the
driver for and run <literal>lsusb</literal> again:
<screen>
$ <userinput>/usr/sbin/lsusb | grep -v 0000:0000</userinput>
Bus 002 Device 003: ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 005 Device 003: ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 004 Device 002: ID 045e:001c Microsoft Corp.
</screen>
The third device is now missing, which means the device shown as:
<screen>
Bus 004 Device 003: ID 157e:300d
</screen>
is the device you want to find the driver for.
</para>
<para>
If you replace the device and look at the output of
<command>lsusb</command> again, the device number will have changed:
<screen>
$ <userinput>/usr/sbin/lsusb | grep 157e</userinput>
Bus 004 Device 004: ID 157e:300d
</screen>
This is because the USB device numbers are not unique, but change every
time they are plugged in. What is stable is the vendor and product ID,
shown here by <command>lsusb</command> as two four-digit
values with a <literal>:</literal> between them. For this device, the
vendor ID is <literal>157e</literal> and the product ID is
<literal>300d</literal>. Write down the values you find, as you will use them in
future steps.
</para>
<para>
As with the PCI device, we will search the kernel source code for the USB
vendor and product IDs in order to find the proper driver to control this
device. Unfortunately, no single file contains all of the USB
vendor IDs, as PCI has. So a search of the whole kernel source tree is
necessary:
<screen>
$ <userinput>grep -i -R -l 157e drivers/*</userinput>
drivers/atm/pca200e.data
drivers/atm/pca200e_ecd.data
drivers/atm/sba200e_ecd.data
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/scsi/ql1040_fw.h
drivers/scsi/ql1280_fw.h
drivers/scsi/qlogicpti_asm.c
</screen>
We know this is a USB wireless device, and not an ATM or SCSI device, so we
can safely ignore the files found in the <filename>atm</filename> and
<filename>scsi</filename> directories. That leaves the
<filename>drivers/net/wireless/zd1211rw/zd_usb.c</filename> filename to
investigate.
</para>
<para>
<filename>zd_usb.c</filename> shows the string
<literal>157e</literal> in the following chunk of code:
<programlisting>
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
{}
};
</programlisting>
Like PCI drivers, USB drivers tell the kernel what devices they support in
order for the kernel to bind the driver to the device. This is done by
using a <literal>struct usb_device_id</literal> variable, as shown here.
This is a list of the different vendor and product IDs that are supported
by this driver. The line:
<programlisting>
{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
</programlisting>