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.
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 |
|
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 ' |