Errata

Linux Device Drivers

Errata for Linux Device Drivers

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
Printed Page General
Multiple Locations

The referenced location to download the source code has been moved on the ORA.com website.

Also, the example code is now completely out of date for current 2.6 kernels!


I have spent the better part of a day examining migration issues of just one example to current kernel conventions:

Examples: kmem_cache_t becomes kmem_cache. NOPAGE_SIGBUS becomes VM_FAULT_NOPAGE, INIT_WORK and kmem_cache_create API's have changed.

The authors may contact me directly by email or call 415-336-6938 if they would like additional updates.

Best regards,
Eric Rabinowitz

Eric Rabinowitz  Apr 16, 2009 
Printed Page p78

The direction for use of the setconsole program states that it should be invoked with a single argument specifying the "number" of the console to receive messages.

What number is the program looking for? For example for /dev/tty0, is it 0, is it the corresponding inode number, is it the major,minor (4,0), is it device file path? An example would help a lot. BTW I built the program using your source code.

Thank you for your time.

Godfrey Vassallo  May 28, 2011 
Mobi Page Location :3003

Unnecessary space is induced after "return retval;" and after before "}"

Anonymous  Mar 27, 2014 
Other Digital Version ch7-sec6
~ paragraph 11

from http://www.makelinux.net/ldd3/?u=chp-7-sect-6


The text says
"The return value from these functions is 0 if the work was successfully added to the queue; a nonzero result means that this work_struct structure was already waiting in the queue, and was not added a second time."

but the return values are actually opposite according to the source code.

Lee Mulcahy  Jun 03, 2014 
Printed Page Page 184
2nd Paragraph

... either jiffies_64 or its least significant bits.

should have been

... either jiffies_64 or its least significant 32 bits.

Ashish Maurya  Nov 02, 2017 
Printed Page 1
scull.init script

from /examples/scull/scull.init

I had problems loading scull.ko using the script scull.init.

That is because the function load_device tries to load the .o file and not the .ko file.

Original version, which does not work:

# Load and create files
function load_device () {

if [ -f $MODDIR/$DEVICE.o ]; then
devpath=$MODDIR/$DEVICE.o
else if [ -f ./$DEVICE.o ]; then
devpath=./$DEVICE.o

...

}

This version works:

# Load and create files
function load_device () {

if [ -f $MODDIR/$DEVICE.ko ]; then
devpath=$MODDIR/$DEVICE.ko
else if [ -f ./$DEVICE.ko ]; then
devpath=./$DEVICE.ko

...

}

Anonymous  Oct 25, 2008 
ePub Page 3.3.1
1st sentence

So far, we have reserved som e device numbers for our use

should read "some" instead of "som e"

Tim Golden  Jun 15, 2014 
Printed Page 7
first section under "Block Devices", 3rd sentence

In the Block Devices section on page 7 there is a sentence that reads, "...which are usually 512 bytes (or a larger power of two) bytes in length."

The word "bytes" incorrectly appears twice. I believe the most grammatically correct solution is to remove the first "bytes".

Anonymous  Sep 04, 2008 
Printed Page 15
last para

"... building modules for 2.6.x requires that you have a configured and built kernel
tree on your system."

Technically, no. All you need (at least for 2.6.18 that I'm playing with) is a tree
that has been configured and had "make modules_prepare" run against it.

Anonymous   
Printed Page 15
near bottom

"... building modules for 2.6.x requires that you have a configured and built kernel
tree on your system."

No, only a tree that's been "make modules_prepare"d. the same inaccurate claim is made
2/3 of the way down p. 17.

Anonymous   
Printed Page 16
code example at the bottom half of the page. Only one example in that page.

I am not a kernel developer. Not sure about the following. Still,
1) For completness.
2) In view of the `Initiallization and Shutdown' section on pages 31 and 32.
3) In order to help newbies.
4) It seems to me that recent 2.6 kernels emit warnings about that.

I would modify:
static int hello_init(void)
to:
static int __init hello_init(void)

and:
static void hello_exit(void)
to:
static void __exit hello_exit(void)

In addition, you should add to the explanation text that, some more aspects of the example
code are elaborated in the `Initiallization and Shutdown' section on pages 31 and 32.

Anonymous   
Printed Page 16
code segment

given that you subsequently recommend putting the MODULE_* macros at the bottom of
the module source, you might want to be consistent and move that MODULE_LICENSE
invocation down as well.

Anonymous   
Printed Page 16
4th

running gcc -c hello.c (or alternately make from the sample code) absolutely does not
work. The author talks about building a kernel tree, but doesn't give any samples as to how to do
this (I believe I have a kernel tree already, but I figured I'd point this out).

I am using both suse 9.2 and 9.3, if this helps out anything. The errors obtained during make are:

/usr/include/linux/jiffies.h:16: error: parse error before jiffies_64
and the errors continue for about 400 lines.

Any clarifications by the author would be most welcomed.

Anonymous   
Printed Page 17
2nd last para

As on p.15, building modules doesn't need a configured and built kernel tree, just a configured and
"make modules_prepare"d tree at least for the latest versions of the kernel. (Perhaps this wasn't
true at the time of printing.)

Anonymous   
Printed Page 26
halfway down

there is no vermagic.o anymore -- instead, there's a "vermagic.h" header file these days.

Anonymous   
Printed Page 26
3rd para

technically, not an error at all, but it might be worth noting that vermagic.o has
been replaced by include/linux/vermagic.h in newer kernsls, just in case readers with
a newer kernel go looking for that file and can't find it.

Anonymous   
Printed Page 26
last line

"version.h" is automatically included by "module.h" ... not these days, it isn't.

Anonymous   
Printed Page 26
Footer

The footers on quite a few even-numbered pages from Chapter 2 on have the wrong chapter number. Chapter 2: pp. 26,32,34; Chapter 3: pp. 58,62; Chapter 4: p. 82; Chapter 5: p. 114; Chapter 6: pp. 142, 158. Surely other chapters have the same error. I stopped looking after chapter six.

Ben  Dec 16, 2010 
Printed Page 29
Fig 2-2

the set of dependencies in Fig 2-2 doesn't appear to match the actual dependencies
(at least in the 2.6.18 kernel.)

the dependencies as listed by "lsmod" for the 2.6.18 kernel is, in part:

...
lp 12872 0
parport_pc 26788 0
parport 36424 2 lp,parport_pc
...

that would seem to differ from what the dependency arrows show in that figure, but
it's possible it was different back in 2.6.10.

Anonymous   
Printed Page 29
Figure 2.2

I'm not sure that picture is technically accurate anymore, but I could be wrong.

Anonymous   
Printed Page 30
1/3 way down

If you already include module.h, then there is no need to additionally include
moduleparam.h since (at least at the moment) module.h includes that heasder file
directly already.

Personally, I think that's a bad idea, and I've even written a wiki page on it:

http://fsdev.net/wiki/index.php?title=Moduleparam.h

Anonymous   
Printed Page 32
middle of page

"If your module does not define a cleanup function, the kernel does not allow it to
be unloaded."

It's not clear if this is still true if you've configured your kernel for forced
unloading and use "rmmod -f". Perhaps that could be clarified.

Anonymous   
Printed Page 34
4th line from bottom

"item2" -> "item1", no?

Anonymous   
Printed Page 40
2/3 way down page

another incorrect reference to vermagic.o, should refer to vermagic.h.

Anonymous   
Printed Page 41
Third line

It should read: "The FIRST form exports (...), and the SECOND limits the export (...)". The
construct FORMER/LATER is also valid.

Anonymous   
Printed Page 41
MODULE_* list

Is there any value in adding MODULE_FIRMWARE or the more generic MODULE_INFO
macros to that list?

Anonymous   
PDF Page 41
under module_param

1. module_param_array should be included in its correct form as was already pointed out in another submission:

module_param_array(name,type,nump,perm);

2. For the module_param listed on page 41, "intarry" is not a valid data type:

"The type can be one of bool, charp, int, invbool, long, short, ushort, uint, ulong, or intarray."

This should be:

"The type can be one of bool, charp, int, invbool, long, short, ushort, uint, or ulong."

Kovacs  Nov 29, 2014 
Printed Page 45
5 lines from bottom

"request_chrdev_region" -> "register_chrdev_region"

Anonymous   
PDF Page 49
the code snippet at the top of p.49

The code is wrong off the positive paths.
1) the call to alloc_chrdev_region (beginning on p.48) could fail, w/o ever filling in dev,
so the code scull_major(dev) within the else block operates on value never initialized
2) the if (result<0) as well doesn't consider the possibility of the failure of alloc_chrdev_region(), only handling the failure of register_chrdev_region() call (on p.48)

Vassilii Khachaturov  Dec 17, 2013 
Printed Page 50
In aio_write() function

loff_t it's not a pointer for this function. Where it is "ssize_t (*aio_write)
(struct kiocb *, const char __user *, size_t, loff_t *)" you should read "ssize_t
(*aio_write) (struct kiocb *, const char __user *, size_t, loff_t)"

Anonymous   
Printed Page 57
Source code block in the 1st paragraph

It seems the line
dev->cdev.ops = &scull_fops;
is redundant because this assignment is done in the previous line
cdev_init(&dev->cdev, &scull_fops);

Anonymous   
Printed Page 57
line 5

int err, devno = MKDEV(scull_major, scull_minor + index);
should be:
int err;
dev_t devno = MKDEV(scull_major, scull_minor + index);

Anonymous   
Printed Page 57
Upper half

Instead of

cdev_init(&dev->cdev, &scull_fops);

It should say

cdev_init(dev->cdev, &scull_fops);


and... -


Instead of

err = cdev_add(&dev->cdev, devno,1);

it should say

err = cdev_add(dev->cdev, devno,1);

Aviel Livay  Apr 26, 2016 
Printed Page 59
last paragraph

"Shut down the device on last close" is misleading, because it supposes release function is called
on every file close. Should read: "Shut down the device"

Anonymous   
Printed Page 62
first para

"writing a single byte in scull consumes 8,000 or 12,000 bytes of memory..."

That total counts the size of the first quantum pointer array and the first quantum,
but shouldn't you also add in the size of the first scull_qset structure you have to
allocate? Sure, it's tiny, but it should still be counted, no?

Anonymous   
Printed Page 68
bottom of page 68 and top of page 69

To be technically correct, sizeof(char *) should say sizeof(void *) since dptr->data
is of type void ** (i.e. pointer to void *).

Anonymous   
Printed Page 74
1/2 way down

CONFIG_INIT_DEBUG does not seem to exist anymore.

Anonymous   
Printed Page 78
Code example and 2nd paragraph

The code example on this page returns "Invalid argument"

# ./setconsole 1
./setconsole: ioctl(stdin, TIOCLINUX): Invalid argument

Code correction: 11 is the TIOCL_SETKMSGREDIRECT cmd number

include/linux/tiocl.h:#define TIOCL_SETKMSGREDIRECT 11 /* restrict kernel
messages to a vt */

Also, drivers/char/vt.c explains TIOCLINUX, not tty_io.c
I'm still trying to figure out why it always returns EINVAL.

My kernel version is:
# uname -r
2.6.17-1.2174_FC5

Anonymous   
PDF Page 81
2nd para from the bottom

Written:

no interrupts can be used to driver the console, even if it is a serial port or a line
printer

Intended: ???

The original verb is apparently replaced with "driver", making this whole part of sentence cryptic. But probably both these lines can be omitted altogether :)

Vassilii Khachaturov  Dec 17, 2013 
Printed Page 82
last line

The filename should probably be /etc/syslog.conf, not /etc/syslogd.conf.

Anonymous   
Printed Page 84
second last para

You refer more than once to "proc_read" when you probably meant to say "read_proc",
just to be consistent.

Anonymous   
Printed Page 85
Code example

Original code:
int limit = count - 80; /* Don't print more than this */

Did you mean something like this:
int limit = (count > 80) ? 80 : count;

Anonymous  Aug 12, 2009 
Printed Page 103
3rd code snippet

There's already an errata to change "mm cf26ac0c" to "mm cf36ac0c", but the output
should also be changed from "0xcf26ac0c = 0x50" to "0xcf36ac0c = 0x50".

Anonymous   
Printed Page 110
bottom of page

I'm guessing you can replace the semaphore-based mutexes with real mutexes based on
mutex.h, at least in some places.

Anonymous   
Printed Page 128
read_seqretry() example

The example shows the read_seqretry() as:

} while read_seqretry(&the_lock, seq);

There must be parenthesis around the condition of 'while' in C.
So the line must be changed to:

} while (read_seqretry(&the_lock, seq));

Anonymous   
Printed Page 141
5th paragraph

FIOQSIZE ioctl returns the size of symbolic link (S_IFLNK) files
as well as regular and directory files.

I think it would be better if the text said: "... when applied to
any other file type such as device files, however, it ..."

Anonymous   
PDF Page 145
ioctl implementation

No semaphore locking the ioctl commands that modify device data. This enables race conditions between multiple processes that all invoke the same ioctl command.

Jonathan  Mar 11, 2019 
Printed Page 149
last para

The descriptions of the return values of the 4 wait_event... macros are misleading,
if not downright wrong.

The last sentence of the paragraph says that wait_event_timeout and
wait_event_interruptible_timeout return 0 on a timeout, but does not describe the
other possible return values:

>0 if the condition became true, no timeout or signal (value is jiffies remaining)

<0 if a signal was received by the process (wait_event_interruptible_timeout only)

For clarity, the return value of wait_event_interruptible should be described as:

=0 if the condition became true, no signal received by the process
<0 if a signal was received by the process

This is compatible with wait_event_interrupible_timeout.

Also, the paragraph should state the wait_event does not have any return value (these
are macros, not functions). The user must not try to store / check a return value for
wait_event.

Note that the descriptions of wait_event and wait_event_interruptible in the 2nd
edition, P. 142, were much better. The wake_up... functions are still properly
described on P. 161 of the 3rd edition, but the good descriptions of the
wait_event... macros disappeared between editions.

The 3rd edition seems to lack that type of clear detailed description of macros and
functions.

Anonymous   
Printed Page 156
Bottom of page, continuing onto top of page 157.

The example of using the DEFINE_WAIT macro on page 156 has the parameter "my_wait." The text on page 157 begins "in which name ..."

"name" does not appear elsewhere on pages 156-7. This is apparently a reference to the string "name" in the definition of the DEFINE_WAIT macro, i.e.

#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)

Perhaps page 156 should say:

DEFINE_WAIT( <name> );
where <name> is the name of the wait queue entry variable, e.g.
DEFINE_WAIT (my_wait);

Thomas K. Johnson  Sep 29, 2010 
Printed Page 159
2nd paragraph

This paragraph explains why there is no problem if the wakeup happens immediately
before the call to schedule(). I think it should also explain why the following
scenario is not a race condition:
a) Wakeup occurs immediately before the call to prepare_to_wait()
b) Call to prepare_to_wait() sets process state to TASK_INTERRUPTIBLE
c) While the spacefree() function is running, the process is pre-empted by an unrelated
process.
d) The process is now still marked as TASK_INTERRUPTIBLE and will therefore not be
re-scheduled and will never execute the call to finish_wait() - so it will sleep
unless/until an interruption comes along...

Anonymous   
PDF Page 159
code

In unconfirmed errata for p. 159 2nd paragraph, anonymous has requested that that paragraph explain why it isn't a problem if a "read wakeup" occurs between the "up" and the "prepare_to_wait", followed by an unrelated preemption after "prepare_to_wait," since it appears that it will not be rescheduled unless/until a subsequent "read wakeup" occurs.

It looks to my "unexpert" eyes like this is a serious bug in the code (seeing it myself is what caused me to lookup this errata to see if it had been reported), and the anonymous requester would have better asked, "Isn't this a serious race condition in this example code (that shows how we ought to do things to avoid such a race)?"

Assuming it is a race that needs to be fixed, it looks to me like the fix is to move the preceding "up()" to just after the "prepare_to_wait()". If it also encompasses the call to spacefree() (though obviously it cannot encompass the call to schedule()) then it would also avoid calling spacefree() when access to dev->rp and dev->wp is not protected.

Thank you!

Douglas Daudelin  Aug 25, 2012 
PDF Page 159
code

Please delete the third paragraph in my previously submitted errata for ?Page 159 code.? The fix suggested there introduces the worse possibility of a deadlock should a preemption occur between the prepare_to_wait() and the up().

Douglas Daudelin  Aug 28, 2012 
Printed Page 160
2nd paragraph from bottom

"Note that there is no way to perform exclusive waits with wait_event and its
variants".

However, in linux-2.6.10/include/linux/wait.h the following is defined:

#define wait_event_interruptible_exclusive(wq, condition)

This disagrees with the above statement.

Anonymous   
Printed Page 169
first paragraph, line 7

"... data structure exactly once ..." [emphasis on precision]
could be better as
"... data structure just once ..." [emphasis on small value]

Anonymous   
Printed Page 169
5th paragraph and code example

The paragraph states: after these two calls,... but the code example seems to do this before.

Anonymous  Aug 21, 2009 
Printed Page 178
code listing for scull_c_open

The authors protect access to data structure by grabbing a spinlock prior to a function call that modifies the structure. However, the function can sleep in kmalloc, which is called while holding the lock.

Anonymous  Nov 13, 2008 
Printed Page 184
2nd paragraph

In the beginning of the second paragraph it is stated that the jiffies counter is initialized to 0.
However, I'm working with version 2.6.15 of the kernel, and the jiffies counter is initialized to
-5 minutes. It is stated in jiffies.h that this is done to help detect errors when jiffies rolls
over.

I encountered this when I was porting a driver from 2.4.22 to 2.6.15.

Anonymous   
Printed Page 184
2nd paragraph

In the argument to read jiffies instead of jiffies_64, you should note that jiffies_64 should *not* be directly read as it is not volatile. If a 64-bit jiffie value is explicitly desired, you should call get_jiffies_64(), which is implemented a simple inline when jiffies is already a 64-bit value However, this function carries the overhead of a lock on other platforms.

Daniel Santos  Jun 14, 2010 
Printed Page 186
last lines

After describing how the TSC can be read from both kernel and user space, the text
refers to <asm/msr.h>, which seems to be available only in kernel space.

And there's no mention of <asm/tsc.h>, which might very well be a post-book development,
I don't know.

Anonymous   
Printed Page 186
5

"...as long as that difference doesnt exceed the overflow
time, you can get the work done without claiming exclusive..."

The difference would never exceed the overflow time. Assume the register is one byte
and wrap around 256. The difference of any two values of unsigned char will not exceed
256, which is the value of the "overflow time". Therefore, It Should be "as long as
that difference doesn't exceed half of the overflow time".

Anonymous   
Printed Page 200
Last paragraph

The timer API description for mod_timer and del_timer_sync show an incorrect return type of int.

The Quick Reference list of same functions on page 270 at end of chapter shows the correct return
value of void for these functions.

Anonymous   
Printed Page 206
2nd paragraph

The text states "The return value from these values is 0 if the work was successfully
added to the queue; a nonzero result means that this work_struct structure was
already waiting...".

The kernel code states the following which indicates that non-zero is success:

/*
* Queue work on a workqueue. Return non-zero if it was successfully
* added.
*
* We queue the work to the CPU it was submitted, but there is no
* guarantee that it will be processed by that CPU.
*/
int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
int ret = 0, cpu = get_cpu();

if (!test_and_set_bit(0, &work->pending)) {
if (unlikely(is_single_threaded(wq)))
cpu = singlethread_cpu;
BUG_ON(!list_empty(&work->entry));
__queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
ret = 1;
}
put_cpu();
return ret;
}

Anonymous   
Printed Page 226
6th paragraph, 2nd sentence

The referenced sentence suggests using readb, yet later on page 251 it
says readb is discouraged and one should use ioread8 instead. Suggest
changing readb on p266 to ioread8.

Anonymous   
Printed Page 226
6th paragraph

Text refers to "readb" function - however on page 251, use of readb is described
as being 'discouraged', so text should refer to "ioread8" function (p251) instead.

Anonymous   
Printed Page 228
last sentence

"it would not do for a processor..."
should read
"it would not do for a process..."

Anonymous   
246
short module

Thank you very much at this BOOK!

On some systems module not correct work. This module normaly load and write value to port (parallel port), byt read every time return 0xff. This problem related with PnP (Plug and Play). Diagnostic this situation: (Thanks by Adam Belay <ambx1[AT]neo.rr[DOT]com> url http://www.mjmwired.net/kernel/Documentation/pnp.txt)

1) cd /sys/devices/pnp0/00:09
2) cat resources
(in my system)
state = disabled
io 0x378-0x37f
irq 5

I not yet fully completed cured short module, but i write own mini module, see below. It work fine.
If you have question mail me.

/*
* $Id: hello.c,v 1.5 2004/10/26 03:32:21 corbet Exp $
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pnp.h>
#include <linux/sysctl.h>

#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
#include <linux/parport.h>
#include <linux/parport_pc.h>
#include <linux/via.h>
#include <asm/parport.h>

#define base 0x378 /* printer port base address */
#define value 243 /* numeric value to send to printer port */
#define value_off 0



static const struct pnp_device_id parport_pc_pnp_tbl[] = {
/* Standard LPT Printer Port */
{.id = "PNP0400", .driver_data = 0},
/* ECP Printer Port */
{.id = "PNP0401", .driver_data = 0},
{ }
};

static struct pnp_driver short_trunc_a_pnp_driver = {
.name = "short_trunc_a",
.id_table = parport_pc_pnp_tbl,
/* .probe = parport_pc_pnp_probe,
.remove = parport_pc_pnp_remove,
*/
};

static int hello_init(void)
{
int r=0;
/* This call Enebled Parallel Port */
pnp_register_driver (&short_trunc_a_pnp_driver);

outb(value, base);
printk(KERN_ALERT "Hello, world\n");
return 0;
}

static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);


Anonymous  Jul 23, 2008 
PDF Page 246
short module

Thank you very much at this BOOK!

On some systems module not correct work. This module normaly load and write value to port (parallel port), byt read every time return 0xff. This problem related with PnP (Plug and Play). Diagnostic this situation: (Thanks by Adam Belay <ambx1[AT]neo.rr[DOT]com> url http://www.mjmwired.net/kernel/Documentation/pnp.txt)

1) cd /sys/devices/pnp0/00:09
2) cat resources
(in my system)
state = disabled
io 0x378-0x37f
irq 5

I not yet fully completed cured short module, but i write own mini module, see below. It work fine.
If you have question mail me.

/*
* $Id: hello.c,v 1.5 2004/10/26 03:32:21 corbet Exp $
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pnp.h>
#include <linux/sysctl.h>

#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
#include <linux/parport.h>
#include <linux/parport_pc.h>
#include <linux/via.h>
#include <asm/parport.h>

#define base 0x378 /* printer port base address */
#define value 243 /* numeric value to send to printer port */
#define value_off 0



static const struct pnp_device_id parport_pc_pnp_tbl[] = {
/* Standard LPT Printer Port */
{.id = "PNP0400", .driver_data = 0},
/* ECP Printer Port */
{.id = "PNP0401", .driver_data = 0},
{ }
};

static struct pnp_driver short_trunc_a_pnp_driver = {
.name = "short_trunc_a",
.id_table = parport_pc_pnp_tbl,
/* .probe = parport_pc_pnp_probe,
.remove = parport_pc_pnp_remove,
*/
};

static int hello_init(void)
{
int r=0;
/* This call Enebled Parallel Port */
pnp_register_driver (&short_trunc_a_pnp_driver);

outb(value, base);
printk(KERN_ALERT "Hello, world\n");
return 0;
}

static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);


Anonymous  Jul 23, 2008 
Other Digital Version 250
first list of funcion

Actually is an error in the code of short.c

this is the patch:

diff --git a/short/short.c b/short/short.c
index 8bd39ed..1ca14f0 100644
--- a/short/short.c
+++ b/short/short.c
@@ -58,6 +58,7 @@ module_param(use_mem, int, 0);
because it's what we want to use in the code */
static unsigned long base = 0x378;
unsigned long short_base = 0;
+unsigned long short_base_pre = 0; // pre remapping
module_param(base, long, 0);

/* The interrupt line is undefined by default. "short_irq" is as above */
@@ -572,8 +573,9 @@ int short_init(void)
return -ENODEV;
}

+ short_base_pre = short_base;
/* also, ioremap it */
- short_base = (unsigned long) ioremap(short_base, SHORT_NR_PORTS);
+ short_base = (unsigned long) ioremap(short_base_pre, SHORT_NR_PORTS);
/* Hmm... we should check the return value */
}
/* Here we register our device - should not fail thereafter */
@@ -681,7 +683,7 @@ void short_cleanup(void)
unregister_chrdev(major, "short");
if (use_mem) {
iounmap((void __iomem *)short_base);
- release_mem_region(short_base, SHORT_NR_PORTS);
+ release_mem_region(short_base_pre, SHORT_NR_PORTS);
} else {
release_region(short_base,SHORT_NR_PORTS);
}

----- EOP -----

In release_mem_region you should not use the remapped address, but the original one, otherwise the resource will not be freed and will fail with:

"Trying to free nonexistent resource <address-range>"

This at least on a similar device on 2.6.17.4 on powerpc arch.

Many thanks for this gorgeous book, I really would like to buy 4th edition as soon as it will be released, maybe updated to >= 2.6.31 and with more documentation on standard interfaces (e.g. kfifo and similar), complex real world examples (video drivers, embedded peripherals...). It was a joy reading and experimenting this book.

Marco Amadori  Aug 06, 2009 
PDF Page 251
First paragraph, last sentence

ioread32_rep reads count 32-bit values starting at buf.

->

ioread32_rep reads count 32-bit values starting at addr.

Anonymous  Nov 18, 2022 
PDF Page 251
First paragraph, first sentence

These functions read or write count values from the given buf to the given addr.

->

These functions read or write count values from the given addr to the given buf.

Anonymous  Nov 18, 2022 
Printed Page 270
3rd full paragraph code example

The code

*index = (new >= (short_buffer + PAGE_SIZE)) ? short_buffer : new;

should read

*index = (new >= (short_buffer + PAGE_SIZE)) ? (short_buffer + (new - short_buffer) % PAGE_SIZE):
new;

The current code works since delta is always 16 but if someone was to try to use this code in a
situation where delta took on other values then index might not be correct when the wrap around
occurred.

Anonymous   
Printed Page 270
short_interrupt(), line 9

Allocation of short_buffer (from the example files):
...
short_buffer = __get_free_pages(GFP_KERNEL,0);
short_head = short_tail = short_buffer;
...

Using short_buffer:
...
/* Write a 16 byte record. Assume PAGE_SIZE is a multiple of 16 */
written = sprintf((char *)short_head,"%08u.%06u
",
(int)(tv.tv_sec % 100000000), (int)(tv.tv_usec));
BUG_ON(written != 16);
...

When the last entry is written to the buffer (e.g. the 256th if PAGE_SIZE is 4096), sprintf() will
write the zero termination character "behind" the buffer. So a variable stored here will be
overwritten with a ''.

Anonymous   
Printed Page 270
Footer

Chapter 1 should be
Chapter 10

Anonymous  Aug 24, 2009 
Printed Page 281
2nd paragraph, 2nd line

"IRQ5 is used for the serial ATA and IEEE1394 controllers;"
should read:
"IRQ5 is used for the serial ATA and USB2 controllers;"

Anonymous   
Printed Page 298
Footer

Chapter 1
should be
Chapter 11

Marcel  Aug 24, 2009 
Printed Page 312
under section void (*remove) (struct pci_dev *dev)

You mentioned that more details about the remove function would be discussed later in
this chapter. I do not see any details regarding the remove function in the chapter.

Anonymous   
Printed Page 314, 326
Enabling the PCI Device, Quick Reference

You explain the function pci_enable_device. Shouldn't the function
pci_disable_device also be shown for completeness?

Anonymous   
Printed Page 317, 326
various, Quick Reference

You explain the functions pci_resource_start, pci_resource_end and pci_resource_flags.
Shouldn't the function pci_resource_len also be there? Especially since the functions
ioremap, ioremap_nocache and io_portmap require the start and length, but not the end.

Anonymous   
Printed Page 317
PCI interrupts section

In recent kernels (at least as recent as 2.6.16) PCI interrupts are handled differently
than described in this section. As far as I can tell the changes are to do ACPI.

In the 2.6.16 kernel you can't get an irq number that works by using.

pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &my_irq);

You have to use the following:

my_irq = dev->irq.

A comment from /usr/src/linux/include/linux/pci.h:

struct pci_dev {
...
...
/*
* Instead of touching interrupt line and base address registers
* directly, use the values stored here. They might be different!
*/
unsigned int irq;
...
...
};

Anonymous   
Printed Page 317
last paragraph

The section "PCI Interrupts" describes how to hook up a pci interrupt by reading the
value programmed into the pci configuration header at PCI_INTERRUPT_LINE, and calling
request_irq() with this value as the first argument. This is incorrect. Consider the
following comment from linux-2.6.10/include/linux/pci.h line 523:

/*
* Instead of touching interrupt line and base address registers
* directly, use the values stored here. They might be different!
*/
unsigned int irq;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions +
expansion ROMs */

The comment states that in a similar manner to the base address registers, one should
not access PCI_INTERRUPT_LINE directly but instead use the value of irq from struct
pci_dev. This is demonstrated in linux-2.6.10/drivers/net/e100.c line 1688, for
example.

Anonymous   
329
Figure 13-1. USB driver overview

In p 11 of O'Reilly's "LPI Linux Certification in a Nutshell, Third Edition" it mentions that "USB core" is below "USB Host controllers" in the stack, which sounds reasonable.

I was wondering where does the error lies: in "Linux Device Drivers" or "LPI Linux Certification in a Nutshell"

Vangelis Katsikaros  Jan 26, 2011 
Printed Page 341
int interval paragraph

"[...] milliseconds. For devices [...]"
should read:
"[...] milliseconds. For high-speed devices [...]"

Anonymous   
PDF Page 350
2nd last line

if (!dev->bulk_out_endpointAddr &&
!(endpoint->bEndpointAddress & USB_DIR_IN) &&
...
--->
if (!dev->bulk_out_endpointAddr &&
!(endpoint->bEndpointAddress & USB_DIR_OUT) &&
...
########################################

Lu Shengliang  Dec 21, 2014 
Printed Page 355
last paragraph

"...so it should do any memory..."
should read:
"...so it should not do any memory..."

Anonymous   
Printed, PDF, ePub, Mobi, , Other Digital Version Page 388
6th paragraph

"IS_ERR described in chaper 1"
should be
"IS_ERR described in chaper 11"

TomV  May 20, 2013 
Printed Page 403
first paragraph after udev heading

The text reads "this has previously been done in user space"
It should read
"this has previously been done in kernel space"

Anonymous   
PDF Page 426
First paragraph code example, line 3

Code example line:
if (remap_pfn_range(vma, vma->vm_start, vm->vm_pgoff,
Should read:
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,

Alexander Levitskiy  Dec 15, 2010 
Printed Page 429
programming example under "Remapping Specific I/O Regions"

"unsigned long psize = simple_region_size - off;"
should be:
"unsigned long psize = simple_region_start + simple_region_size - off);"

Anonymous   
Other Digital Version 429
Example, before last paragraph

It seems this was corrected from an earlier version, but it is still not quite correct.

The example provides sample code outlining how to memory map a particular region in memory.

unsigned long pfn = page_to_pfn(simple_region_start + off);

This is a problem. page_to_pfn() accepts a page struct as an argument. "simple_region_start" and "off" are *not* page structs, but rather a physical address and an address offset. This is seen by the code:

unsigned long off = vma->vm_pgoff << PAGE_SHIFT;

and in the paragraph before: "...beginning at physical address simple_region_start (which should be page-aligned)..."

To correct this, one should do:

unsigned long pfn = (simple_region_start + off) >> PAGE_SHIFT;

This generates the correct page frame number.


Anonymous  Oct 09, 2008 
Printed Page 438
Top two code samples

Beginning (at least) with 2.6.18 the second parameter to aio_read and aio_write
is an iovec pointer instead of a pointer to a char buffer with the third parameter,
count, indicating the number of iovecs. This issue, of course, affects all of "An
Asynchronous I/O example" on pages 439 and 440.

As an aside, this affects building the sample scullX drivers on fedora core 5 and 6
machines. Also note that main.c in those example drivers includes <linux/config.h>.
With Fedora core 6 you don't need full source to develop and test modules, just the
kernel-devel set. The Fedora core 6 system no longer includes kernel source and
recommends building external modules with just kernel-devel.

<linux/config.h> is not present, at least on my Fedora core 6 system with kernel-devel
loaded. It does not seem to be needed (if you ignore compile warnings that the file
doesn't exist) to build scullc etc.

My builds of scullc, etc., on an older Fedora Core system with source present succeed
as shipped since this is a 2.14 system and aio_read|write uses a char pointer for the
second parameter.

Anonymous   
PDF Page 470
first code sample and last code sample (code line is repeated)

The sample code is given as

set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));

but that will lead to integer truncation if hardsect_size is smaller than KERNEL_SECTOR_SIZE. In fact, it will set the capacity to zero, no matter how many actual sectors the device has.

Instead, you probably want to change that to something like

set_capacity(dev->gd, (nsectors*hardsect_size)/KERNEL_SECTOR_SIZE));

but now you have the chance to overflow on the multiplication.

For a full solution, you probably want a simple if-else:

if (hardsect_size < KERNEL_SECTOR_SIZE)
set_capacity(dev->gd, nsectors/(KERNEL_SECTOR_SIZE/hardsect_size));
else
set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));

The above will handle both cases correctly while minimizing the chance of an overflow.

Anonymous  Aug 26, 2010 
Printed Page 475
Section "A Simple request Method"

It looks that the example code sbull_request()("the simplest possible request method") may not work correctly when the req (received from elv_next_request(q)) contains multiple bio and bio_vec in it. It's because it tries to copy from/to a contiguous memory area pointed by req->buffer though it actually needs to copy from/to non-contiguous multiple pages pointed by each bio_vec. If it's true, you'd better add a note saying it's a sort of pseudo-code and has a limitation described above.

Anonymous  Nov 05, 2009 
Printed Page 488
definition of sbull_xfre_bio() routine

There are two problems with this routine.

First problem is obviously a typo: the line

__bio_kunmap_atomic(bio,KM_USER0);
should be
__bio_kunmap_atomic(buffer,KM_USER0);

as described on page 483.

Second problem is that sbull_xfer_bio() calls bio_cur_sectors(bio)
as it goes through the loop. The bio_cur_sectors(bio) is defined
in <linux/bio.h> as bio->bi_io_vec[bio->bi_idx]. Since your routine
never increments bio->bi_idx, it will work only if all segments of
this 'bio' have exactly the same size; it is unable to handle
the case when different segments have different sizes. I think this
problem can be solved by replacing calls to bio_cur_sectors(bio)
with (bvec->bv_len >> KERNEL_SECTOR_SIZE).

Anonymous   
Printed Page 556
tiny_write() sample code

The paragraph above says that you're not supposed to sleep in write() callback, since
it can be called from interrupt context, but the sample code for tiny_write uses
down().

Anonymous   
Other Digital Version 556
Sample code 'tiny_write'

The text states that the write function of a TTY driver should return the number of characters successfully written to the device. However, the sample code will always return either -EINVAL or -ENODEV.

Aliz Hammond  May 21, 2012 
Printed Page 559
2nd, 3rd and 5th paragraphs

As of 2.6.15 tty flip buffers have now changed. See Alan Cox comment below.

Alan Cox patch 2.6.15-rc1

This replaces the tty flip buffers with kmalloc objects in rings. In the
normal situation for an IRQ driven serial port at typical speeds the
behaviour is pretty much the same, two buffers end up allocated and the
kernel cycles between them as before.

When there are delays or at high speed we now behave far better as the
buffer pool can grow a bit rather than lose characters. This also means
that we can operate at higher speeds reliably.

The following might be a suitable substitute for the example code

for (i = 0; i < data_size; ++i) {
if (tty_request_buffer_room(tty, 1) == 0)
break;
tty_insert_flip_char(tty, data[i], TTY_NORMAL);
}
tty_schedule_flip(tty);

[sample code] in file scull/pipe.c, scull_p_open method;
Every invocation of the scull_p_open method will reset the read and write pointers
(rp, wp) to buffer beginning. Doing so will cause a deadlock by putting the reader
and writer in an infinite sleep in some situations.

*To reproduce the bug:
- cat "file_BIGGER_than_buffer_size" > /dev/scullpipe0
- "cat" will sleep cause the buffer is full
- cat /dev/scullpipe0
- Buffer pointers will be reset by the statement dev->rp=dev->wp=dev->buffer. cat
will sleep thinking that the buffer is empty (dev->rp == dev->wp)
- reader and writer will infinitly sleep

* Solution:
Buffer pointers shouldn't be reset if any process opened the device before us (and
possibly changed rp or wp). Check could be done using the reference counters nreaders
and nwriters.

--- pipe.c 2006-12-22 04:21:23.000000000 +0200
+++ pipe.c 2006-12-22 06:26:24.000000000 +0200
@@ -75,9 +75,11 @@
return -ENOMEM;
}
}
- dev->buffersize = scull_p_buffer;
- dev->end = dev->buffer + dev->buffersize;
- dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */
+ if (dev->nreaders == 0 && dev->nwriters == 0) {
+ dev->buffersize = scull_p_buffer;
+ dev->end = dev->buffer + dev->buffersize;
+ dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */
+ }

Anonymous   
PDF Page 10000
n/a

There is a need for a chapter on embedded issues. In particular how device discovery and the flattened device tree work.

David Braun  Apr 26, 2013