PrintNumber ErrorLocation Error Correction DateAdded
2 p iv update copright page fixed 6/25/2008
2 p xxvii Sometimes, for simplicity, the book uses generic references. So if the text points you to the arch/your-arch/ directory, it should be translated, for example, to arch/x86/ if you are compiling the kernel for the x86 architecture. Similarly, any mention of the include/asm-your-arch/ directory should be read as include/asm-arm/ if you are, for instance, building the kernel for the ARM architecture. The * symbol and X are Sometimes, for simplicity, the book uses generic references. So, if the text points you to the arch/your-arch/ directory, it should be translated, for example, to arch/x86/ if you are compiling the kernel for the x86 architecture. Similarly, any mention of the include/asm-your-arch/ directory should be read as include/asm-arm/ if you are, for instance, building the kernel for the ARM architecture. The * symbol and X are 6/25/2008
2 p xxviii occasionally used as wildcard characters in filenames. So, if a chapter asks you to look at include/linux/time*.h, look at the header files, time.h, timer.h, times.h, and timex.h residing in the include/linux/ directory. If a section talks about /dev/input/eventX or /sys/devices/platform/i8042/serioX/, X is the interface number that the kernel assigns to your device in the context of your system configuration.
occasionally used as wildcard characters in filenames. So, if a chapter asks you to look at include/linux/time*.h, look at the header files, time.h, timer.h, times.h, and timex.h residing in the include/linux/ directory. If a section talks about /dev/input/eventX or /sys/devices/platform/i8042/serioX/, X is the interface number that the kernel assigns to your device in the context of your system configuration.
6/25/2008
2 p xxx Sreekrishnan Venkateswaran has a master’s degree in computer science from the Indian Institute of Technology, Kanpur, India. During the past 12 years that he has been working for IBM, he has ported Linux to various embedded devices such as a wristwatch, handheld, music player, VoIP phone, pacemaker programmer, and remote patient monitoring system. Sreekrishnan was a contributing editor and kernel columnist to the Linux Magazine for more than 2 years. Currently, he manages the embedded solutions group at IBM India.
Sreekrishnan Venkateswaran has a master’s degree in computer science from the Indian Institute of Technology, Kanpur, India. During the past 12 years that he has been working for IBM, he has ported Linux to devices such as wristwatches, PDAs, and music players to VoIP phones, pacemaker programmers, and remote patient monitoring systems. Sreekrishnan was a contributing editor and kernel columnist to the Linux Magazine for more than 2 years. Currently, he manages the embedded solutions group at IBM India.
6/25/2008
2 p 3 There are different flavors of free software. One such flavor is called public domain software. Software released under the public domain is not copyrighted, and no restrictions are imposed on its usage. You can use it for free, make changes to it, and even restrict the distribution of your modified sources. As you can see, the “no restrictions” clause introduces the power to introduce restrictions downstream.
There are different flavors of free software. One such flavor is called public domain software. Software released under the public domain is not copyrighted, and no restrictions are imposed on its usage. You can use it for free, make changes to it, and even restrict the distribution of your modified sources. As you can see, the “no restrictions” clause introduces the power to impose restrictions downstream.
6/25/2008
2 p 6 First, go to www.kernel.org and get the latest stable tree. The sources are archived as tar files compressed in both gzip (.gz) and bzip2 (.bz2) formats. Obtain the source files by uncompressing and untarring the zipped tar ball. In the following commands, replace X.Y.Z with the latest kernel version, such as 2.6.23:
First, go to www.kernel.org and get the latest stable tree. The sources are archived as tar files compressed in both gzip (.gz) and bzip2 (.bz2) formats. Obtain the source files by uncompressing and untarring the zipped tar ball. In the following commands, replace X.Y.Z with the latest kernel version, such as 2.6.24:
6/25/2008
2 p 10 GCC options You may ask GCC to generate preprocessed source code using the -E option. Preprocessed code contains header file expansions and reduces the need to hop-skip through nested include files to expand multiple levels of macros. Here is a usage example to pre-process drivers/char/mydrv.c and produce expanded output in mydrv.i: GCC options You may ask GCC to generate preprocessed source code using the -E option. Preprocessed code contains header file expansions and reduces the need to hop-skip through nested include files to expand multiple levels of macros. Here is a usage example to pre-process drivers/char/mydrv.c and produce expanded output in mydrv.i: 6/25/2008
2 p 12 The following utilities are available to manipulate modules: insmod, rmmod, lsmod, modprobe, modinfo, and depmod. The first two are utilities to insert and remove modules, whereas lsmod lists the modules that are currently loaded. modprobe is a cleverer version of insmod that also inserts dependent modules after examining the contents of /lib/modules/X.Y.Z/modules.dep. For example, assume that you need to mount a Virtual File Allocation Table (VFAT) partition present on a USB pen drive. Use modprobe to load the VFAT filesystem driver:
The following utilities are available to manipulate modules: insmod, rmmod, lsmod, modprobe, modinfo, and depmod. The first two are utilities to insert and remove modules, whereas lsmod lists the modules that are currently loaded. modprobe is a cleverer version of insmod that also inserts dependent modules after examining the contents of /lib/modules/X.Y.Z/modules.dep. For example, assume that you need to mount a Virtual File Allocation Table (VFAT) partition present on a USB pen drive. Use modprobe to load the VFAT filesystem driver:
6/25/2008
2 p 13 As you see in the lsmod output, modprobe inserts three modules rather than one. modprobe first figures out that it has to insert /lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko. But when it peeks into the dependency file /lib/modules/X.Y.Z/modules.dep, it finds the following line and realizes that it has to load two other dependent modules first:
/lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko:
/lib/modules/X.Y.Z/kernel/fs/fat/fat.ko
/lib/modules/X.Y.Z/kernel/fs/nls/nls_base.ko
It then proceeds to load fat.ko and nls_base.ko before attempting to insert vfat.ko, thus automatically loading all the modules you need to mount your VFAT partition.
Use the modinfo utility to extract verbose information about the modules you just loaded:
bash> modinfo vfat
filename: /lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko
license: GPL
description: VFAT filesystem support
...
depends: fat, nls_base
To compile a kernel driver as a module, toggle the corresponding menu choice button to <M> while configuring the kernel. Most of the device driver examples in this book are implemented as kernel modules. To build a module mymodule.ko from its source file mymodule.c, create a one-line Makefile and execute it as follows:
As you see in the lsmod output, modprobe inserts three modules rather than one. modprobe first figures out that it has to insert /lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko. But when it peeks into the dependency file /lib/modules/X.Y.Z/modules.dep, it finds the following line and realizes that it has to load two other dependent modules first:
/lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko:
/lib/modules/X.Y.Z/kernel/fs/fat/fat.ko
/lib/modules/X.Y.Z/kernel/fs/nls/nls_base.ko
It then proceeds to load fat.ko and nls_base.ko before attempting to insert vfat.ko, thus automatically loading all the modules you need to mount your VFAT partition.
Use the modinfo utility to extract verbose information about the modules you just loaded:
bash> modinfo vfat
filename: /lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko
license: GPL
description: VFAT filesystem support
...
depends: fat, nls_base
To compile a kernel driver as a module, toggle the corresponding menu choice button to <M> while configuring the kernel. Most of the device driver examples in this book are implemented as kernel modules. To build a module mymodule.ko from its source file mymodule.c, create a one-line Makefile and execute it as follows:
6/25/2008
2 p 18 The first-level kernel initializations are done in real mode assembly. Subsequent startup is performed in protected mode by the function start_kernel() defined in init/main.c, the source file you modified in the previous chapter. start_-kernel() begins by initializing the CPU subsystem. The first-level kernel initializations are done in real mode assembly. Subsequent startup is performed in protected mode by the function start_kernel() defined in init/main.c, the source file you modified in the previous chapter. start_-kernel() begins by initializing the CPU subsystem. 6/25/2008
2 p 20 only lines 3, 7, 9, 13, 18, 22, 27, 30, 58, and 60 should be bold fixed 6/25/2008
2 p 22 Command-line arguments affect the code path traversed during boot. As a simple example, assume that the command-line argument of interest is called bootmode. If this parameter is set to 1, you would like to print some debug messages during boot and switch to a runlevel of 3 at the end of the boot. (Wait until the boot messages are printed out by the init process to learn the semantics of runlevels.) If bootmode is instead set to 0, you would prefer the boot to be relatively laconic, and the runlevel set to 2. Because you are already familiar with init/main.c, let’s add the following modification to it:
Command-line arguments affect the code path traversed during boot. As a simple example, assume that the command-line argument of interest is called bootmode. If this parameter is set to 1, you would like to print some debug messages during boot and switch to a runlevel of 3 at the end of the boot. (Wait until the boot messages are printed out by the init process to learn the semantics of runlevels.) If bootmode is instead set to 0, you would prefer the boot to be relatively laconic, and the runlevel set to 2. Because you are already familiar with init/main.c, let’s add the following modification to it:
6/25/2008
2 23 During boot, the kernel calculates the number of times the processor can execute an internal delay loop in one jiffy, which is the time interval between two consecutive ticks of the system timer. As you would expect, the calculation has to be calibrated to the processing speed of your CPU. The result of this calibration is stored in a kernel variable called loops_per_jiffy. One place where the kernel makes use of loops_per_jiffy is when a device driver desires to delay execution for small durations in the order of microseconds.
During boot, the kernel calculates the number of times the processor can execute an internal delay loop in one jiffy, which is the time interval between two consecutive ticks of the system timer. As you would expect, the calculation has to be calibrated to the processing speed of your CPU. The result of this calibration is stored in a kernel variable called loops_per_jiffy. One place where the kernel makes use of loops_per_jiffy is when a device driver desires to delay execution for small durations in the order of microseconds.
6/25/2008
2 p 24 The preceding code begins by assuming that loops_per_jiffy is greater than 4096, which translates to a processor speed of roughly one million instructions per second (MIPS). It then waits for a fresh jiffy to start and executes the delay loop, __delay(loops_per_jiffy). If the delay loop outlasts the jiffy, the previous value of loops_per_jiffy (obtained by bitwise right-shifting it by one) fixes its most significant bit (MSB). Otherwise, the function continues by checking whether it will obtain the MSB by bitwise left-shifting loops_per_jiffy. When the kernel thus figures out the MSB of loops_per_jiffy, it works on the lower-order bits and fine-tunes its precision as follows:
The preceding code begins by assuming that loops_per_jiffy is greater than 4096, which translates to a processor speed of roughly one million instructions per second (MIPS). It then waits for a fresh jiffy to start and executes the delay loop, __delay(loops_per_jiffy). If the delay loop outlasts the jiffy, the previous value of loops_per_jiffy (obtained by bitwise right-shifting it by one) fixes its most significant bit (MSB). Otherwise, the function continues by checking whether it will obtain the MSB by bitwise left-shifting loops_per_jiffy. After the kernel thus figures out the MSB of loops_per_jiffy, it works on the lower-order bits and fine-tunes its precision as follows:
6/25/2008
2 p 26 Initramfs, like the page cache over which it’s built, grows and shrinks dynamically unlike initrd and, hence, reduces memory wastage. Also, unlike initrd, which requires you to include the associated filesystem driver (e.g., EXT2 drivers if you have an EXT2 filesystem on your initrd), initramfs needs no filesystem support. The initramfs code is tiny because it’s just a small layer on top of the page cache.
You can pack your initial root filesystem into a compressed cpio archive and pass it to the kernel command line using the initrd= argument or build it as part of the kernel image using the INITRAMFS_SOURCE menu option during kernel configuration. With the latter, you may either provide the filename of a cpio archive or the path name to a directory tree containing your initramfs layout. During boot, the kernel extracts the files into an initramfs root filesystem (also called rootfs) and executes a top-level /init program if it finds one. This method of obtaining an initial rootfs is especially useful for embedded platforms, where all system resources are at a premium. To create an initramfs image, use mkinitramfs. Look at Documentation/filesystems/ramfs-rootfs-initramfs.txt for more documentation.
In this case, we are using initramfs by supplying a compressed cpio archive of the initial root filesystem to the kernel using the initrd= command-line argument. After unpacking the contents of the archive into rootfs, the kernel frees the memory where the archive resides (387K in this case) and announces the above boot message. The freed pages are then doled out to other parts of the kernel that request memory.
As discussed in Chapter 18, initrd and initramfs are sometimes used to hold the actual root filesystem on embedded devices during development.
Initramfs, like the page cache over which it’s built, grows and shrinks dynamically unlike initrd, and hence reduces memory wastage. Also, unlike initrd, which requires you to include the associated filesystem driver (e.g., EXT2 drivers if you have an EXT2 filesystem on your initrd), initramfs needs no filesystem support. The initramfs code is tiny because it’s just a small layer on top of the page cache.
You can pack your initial root filesystem into a compressed cpio archive and pass it to the kernel command line using the initrd= argument or build it as part of the kernel image using the INITRAMFS_SOURCE menu option during kernel configuration. With the latter, you may either provide the filename of a cpio archive or the path name to a directory tree containing your initramfs layout. During boot, the kernel extracts the files into an initramfs root filesystem (also called rootfs) and executes a top-level /init program if it finds one. This method of obtaining an initial rootfs is especially useful for embedded platforms, where all system resources are at a premium. To create an initramfs image, use mkinitramfs. Look at Documentation/filesystems/ramfs-rootfs-initramfs.txt for more documentation.
In this case, we are using initramfs by supplying a compressed cpio archive of the initial root filesystem to the kernel using the initrd= command-line argument. After unpacking the contents of the archive into rootfs, the kernel frees the memory where the archive resides (387K in this case) and announces the above boot message. The freed pages are then doled out to other parts of the kernel that request memory.
As we will discuss in Chapter 18, initrd and initramfs are sometimes used to hold the actual root filesystem on embedded devices during development.
6/25/2008
2 p 27 The main goal of an I/O scheduler is to increase system throughput by minimizing disk seek times, which is the latency to move the disk head from its existing position to the disk sector of interest. The 2.6 kernel provides four different I/O schedulers: Deadline, Anticipatory, Complete Fair Queuing, and Noop. As the preceding kernel message indicates, the kernel sets Anticipatory as the default I/O scheduler. We look at I/O scheduling in Chapter 14, “Block Drivers.”
The main goal of an I/O scheduler is to increase system throughput by minimizing disk seek times, which is the latency to move the disk head from its existing position to the disk sector of interest. The 2.6 kernel provides four different I/O schedulers: Deadline, Anticipatory, Complete Fair Queuing, and Noop. As the preceding kernel message indicates, the kernel sets Anticipatory as the default I/O scheduler. We look at I/O scheduling in Chapter 14, “Block Drivers.”
6/25/2008
2 p 30 The kernel accomplishes useful work using a combination of process contexts and interrupt contexts. Kernel code that services system calls issued by user applications runs on behalf of the corresponding application processes and is said to execute in process context. Interrupt handlers, on the other hand, run asynchronously in interrupt context. Processes contexts are not tied to any interrupt context and vice versa. The kernel accomplishes useful work using a combination of process contexts and interrupt contexts. Kernel code that services system calls issued by user applications runs on behalf of the corresponding application processes and is said to execute in process context. Interrupt handlers, on the other hand, run asynchronously in interrupt context. Processes contexts are not tied to any interrupt context and vice versa. 6/25/2008
2 p 31 The working of many parts of the kernel is critically dependent on the passage of time. The Linux kernel makes use of different timers provided by the hardware to provide time-dependent services such as busy-waiting and sleep-waiting. The processor wastes cycles while it busy-waits but relinquishes the CPU when it sleep-waits. Naturally, the former is done only when the latter is not feasible. The kernel also facilitates scheduling of functions that desire to run after a specified time duration has elapsed.
The working of many parts of the kernel is critically dependent on the passage of time. The Linux kernel makes use of different timers supported by the hardware to provide time-dependent services such as busy-waiting and sleep-waiting. The processor wastes cycles while it busy-waits but relinquishes the CPU when it sleep-waits. Naturally, the former is done only when the latter is not feasible. The kernel also facilitates scheduling of functions that desire to run after a specified time duration has elapsed.
6/25/2008
2 p 35 You may use mod_timer() to change the expiration of my_timer, del_timer() to cancel my_timer, and timer_pending() to see whether my_timer is pending at the moment. If you look at kernel/timer.c, you will find that schedule_timeout() internally uses these same APIs.
You may use mod_timer() to change the expiration of my_timer, del_timer() to cancel my_timer, and timer_pending() to see whether my_timer is pending at the moment. If you look at kernel/timer.c, you will find that schedule_timeout() internally uses these same APIs.
6/25/2008
2 p 36 Busy-waiting for short durations is accomplished by measuring the time the processor takes to execute an instruction and looping for the necessary number of iterations. As discussed earlier in this chapter, the kernel performs this measurement during boot and stores the value in a variable called loops_per_jiffy. The short-delay APIs use loops_per_jiffy to decide the number of times they need to busy-loop. To achieve a 1-microsecond delay during a handshake process, the USB host controller driver, drivers/usb/host/ehci-hcd.c, calls udelay(), which internally uses loops_per_jiffy: Busy-waiting for short durations is accomplished by measuring the time the processor takes to execute an instruction and looping for the necessary number of iterations. As discussed earlier in this chapter, the kernel performs this measurement during boot and stores the value in a variable called loops_per_jiffy. The short-delay APIs use loops_per_jiffy to decide the number of times they need to busy-loop. To achieve a 1-microsecond delay during a handshake process, the USB host controller driver drivers/usb/host/ehci-hcd.c, calls udelay(), which internally uses loops_per_jiffy: 6/25/2008
2 p 43 If preemption is enabled, mere disabling of interrupts won’t protect your critical region from being trampled over. There is the possibility of multiple threads simultaneously entering the critical section in process context. Referring back to Figure 2.4 in this scenario, Thread A and Thread B now need to protect themselves against each other in addition to guarding against Thread C. The solution apparently, is to disable kernel preemption before the start of the critical section and reenable it at the end, in addition to disabling/reenabling interrupts. For this, Thread A and Thread B use the irq variant of spinlocks:
If preemption is enabled, mere disabling of interrupts won’t protect your critical region from being trampled over. There is the possibility of multiple threads simultaneously entering the critical section in process context. Referring back to Figure 2.4 in this scenario, Thread A and Thread B now need to protect themselves from each other in addition to guarding against Thread C. The solution apparently, is to disable kernel preemption before the start of the critical section and reenable it at the end, in addition to disabling/reenabling interrupts. For this, Thread A and Thread B use the irq variant of spinlocks:
6/25/2008
2 p 46 Like regular spinlocks, reader-writer locks also have corresponding irq variants—namely, read_lock_irqsave(), read_lock_irqrestore(), write_lock_irqsave(), Like regular spinlocks, reader-writer locks also have corresponding irq variants—read_lock_irqsave(), read_lock_irqrestore(), write_lock_irqsave(), 6/25/2008
2 p 47 Sequence locks or seqlocks, introduced in the 2.6 kernel, are reader-writer locks where writers are favored over readers. This is useful if write operations on a variable far outnumber read accesses. An example is the jiffies_64 variable discussed earlier in this chapter. Writer threads do not wait for readers who may be inside a critical section. Because of this, reader threads may discover that their entry inside a critical section has failed and may need to retry:
Sequence locks or seqlocks, introduced in the 2.6 kernel, are reader-writer locks where writers are favored over readers. This is useful if write operations on a variable far outnumber read accesses. An example is the jiffies_64 variable discussed earlier in this chapter. Writer threads do not wait for readers who may be inside a critical section. Because of this, reader threads may discover that their entry inside a critical section has failed and may need to retry:
6/25/2008
2 p 49 Some device drivers have to be aware of the existence of memory zones. In addition, many drivers need the services of memory-allocation functions. In this section, let’s briefly discuss both.
Some device drivers have to be aware of the existence of memory zones. In addition, many drivers need the services of memory allocation functions. In this section, let’s briefly discuss both.
6/25/2008
2 p 51 1. GFP_KERNELUsed by process context code to allocate memory. If this flag is specified, kmalloc() is allowed to go to sleep and wait for pages to get freed up.
2. GFP_ATOMICUsed by interrupt context code to get hold of memory. In this mode, kmalloc() is not allowed to sleep-wait for free pages, so the probability of successful allocation with GFP_ATOMIC is lower than with GFP_KERNEL.
1. GFP_KERNEL: Used by process context code to allocate memory. If this flag is specified, kmalloc() is allowed to go to sleep and wait for pages to get freed up.
2. GFP_ATOMIC: Used by interrupt context code to get hold of memory. In this mode, kmalloc() is not allowed to sleep-wait for free pages, so the probability of successful allocation with GFP_ATOMIC is lower than with GFP_KERNEL.
6/25/2008
2 p 58 The events/n threads (where n is the CPU number) help implement work queues, which are another way of deferring work in the kernel. Parts of the kernel that desire deferred execution of work can either create their own work queue or make use of the default events/n worker thread. Work queues are also dissected in Chapter 4.
The events/n threads (where n is the CPU number) help implement work queues, which are another way of deferring work in the kernel. Parts of the kernel that desire deferred execution of work can either create their own work queue or make use of the default events/n worker thread. Work queues are also dissected in Chapter 4.
6/25/2008
2 p 63 User Mode Helpers
Mykthread invokes run_umode_handler() in Listing 3.1 to notify user space about detected events:
User Mode Helpers
To notify user space of detected events, mykthread invokes run_umode_handler() in Listing 3.1.
6/25/2008
2 p 69 After executing a submitted work function, the worker thread removes the corresponding node from the list using list_del(). Note that mydrv_wq.lock is released and reacquired in the time window when the submitted work function is executed. This is because work functions can go to sleep resulting in potential deadlocks if newly scheduled code tries to acquire the same spinlock.
After executing a submitted work function, the worker thread removes the corresponding node from the list using list_del(). Note that mydrv_wq.lock is released for the time window during which the submitted work function is executed. This is because work functions can go to sleep resulting in potential deadlocks if newly scheduled code tries to acquire the same spinlock.
6/25/2008
2 p 74 If you are using work queues, you will get linker errors unless you declare your module as licensed under GPL. This is because the kernel exports these functions only to GPLed code. If you look at the kernel work queue implementation, you will see this restriction expressed in statements such as this:
If you are using work queues, you will get linker errors unless you declare your module as licensed under GPL. This is because the kernel exports these functions only to GPL’ed code. If you look at the kernel work queue implementation, you will see this restriction expressed in statements such as this: 6/25/2008
2 p 75 An example user of notifiers is the High-level Data Link Control (HDLC) protocol driver drivers/net/wan/hdlc.c, which registers itself with the net device notifier chain to sense carrier changes.
An example user of notifiers is the High-level Data Link Control (HDLC) protocol driver drivers/net/wan/hdlc.c, which registers itself with the net device notifier chain to sense carrier changes.
6/25/2008
2 p 81 Kthread Helpers
Kthread helpers add a coating over the raw thread creation routines and simplify the task of thread management.
Kthread Helpers
Kthread helpers add a coating over the raw thread creation routines and simplify the task of thread management.
6/25/2008
2 p 82 - daemonize("my_thread");

- while (1) {
+ /* Continue work if no other thread has
+ * invoked kthread_stop() */
+ while (!kthread_should_stop()) {
/* ... */
- /* Quit if let go */
- if (pink_slip) {
- break;
- }
/* ... */
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&my_thread_wait, &wait);
- daemonize("my_thread");

- while (1) {
+ /* Continue work if no other thread has
+ * invoked kthread_stop() */
+ while (!kthread_should_stop()) {
/* ... */
- /* Quit if let go */
- if (pink_slip) {
- break;
- }
/* ... */
}
/* Bail out of the wait queue */
__set_current_state(TASK_RUNNING);
remove_wait_queue(&my_thread_wait, &wait);
6/25/2008
2 p 97 spinlock_t roller_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(roller_poll);

static irqreturn_t
roller_interrupt(int irq, void *dev_id)
{
int i, PA_t, PA_delta_t, movement = 0;

/* Get the waveforms from bits 0, 1 and 2
of Port D as shown in Figure 4.3 */
PA_t = PORTD & 0x07;

/* Wait until the state of the pins change.
(Add some timeout to the loop) */
for (i=0; (PA_t==PA_delta_t); i++){
PA_delta_t = PORTD & 0x07;
}
spinlock_t roller_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(roller_poll);

static irqreturn_t
roller_interrupt(int irq, void *dev_id)
{
int i, PA_t, PA_delta_t, movement = 0;

/* Get the waveforms from bits 0, 1 and 2
of Port D as shown in Figure 4.3 */
PA_t =PA_delta_t = PORTD & 0x07;

/* Wait until the state of the pins change.
(Add some timeout to the loop) */
for (i=0; (PA_t==PA_delta_t); i++){
PA_delta_t = PORTD & 0x07;
}
6/25/2008
2 p 99 Let’s end this section by introducing some functions that enable and disable interrupts on a particular IRQ. enable_irq(ROLLER_IRQ) enables interrupt generation when the roller wheel moves, while disable_irq(ROLLER_IRQ) does the reverse. disable_irq_nosync(ROLLER_IRQ) disables roller interrupts but does not wait for any currently executing instance of roller_interrupt() to return. This nosync flavor of disable_irq() is faster but can potentially cause race conditions. Use this only when you know that there can be no races. An example user of disable_irq_nosync() is drivers/ide/ide-io.c, which blocks interrupts during initialization, because some systems have trouble with that.
Let’s end this section by introducing some functions that enable and disable interrupts on a particular IRQ. enable_irq(ROLLER_IRQ) enables interrupt generation when the roller wheel moves, while disable_irq(ROLLER_IRQ) does the reverse. disable_irq_nosync(ROLLER_IRQ) disables roller interrupts but does not wait for any currently executing instance of roller_interrupt() to return. This nosync flavor of disable_irq() is faster but can potentially cause race conditions. Use this only when you know that there can be no races. An example user of disable_irq_nosync() is drivers/ide/ide-io.c, which blocks interrupts during initialization, because some systems have trouble with that.
6/25/2008
2 p 101 Listing 4.3 Using Tasklets to Offload Work from Interrupt Handlers
struct roller_device_struct { /* Device-specific structure */
/* ... */
struct tasklet_struct tsklt;
/* ... */
}

void __init roller_init()
{
Listing 4.3 Using Tasklets to Offload Work from Interrupt Handlers
struct roller_device_struct { /* Device-specific structure */
/* ... */
struct tasklet_struct tsklt;
/* ... */
};

void __init roller_init()
{
6/25/2008
2 p 104 To understand how to use udev, let’s look at an example. Assume that you have a USB DVD drive and a USB CD-RW drive. Depending on the order in which you hotplug these devices, one of them is assigned the name /dev/sr0, and the other gets the name /dev/sr1. During pre-udev days, you had to figure out the associated names before you could use the devices. But with udev, you can consistently view the DVD (as say, /dev/usbdvd) and the CD-RW (as say, /dev/usbcdrw) irrespective of the order in which they are plugged in or out.
To understand how to use udev, let’s look at an example. Assume that you have a USB DVD drive and a USB CD-RW drive. Depending on the order in which you hotplug these devices, one of them is assigned the name /dev/sr0, and the other gets the name /dev/sr1. During pre-udev days, you had to figure out the associated names before you could use the devices. But with udev, you can consistently view the DVD (as say, /dev/usbdvd) and the CD-RW (as say, /dev/usbcdrw) irrespective of the order in which they are plugged in or out.
6/25/2008
2 p 106 /dev/usbdvd, and your CD-RW drive always appears as /dev/usbcdrw. You can deterministically mount them from shell scripts using commands such as these:
/dev/usbdvd, and your CD-RW drive always appears as /dev/usbcdrw. You can deterministically mount them from shell scripts using commands such as this:
6/25/2008
2 p 110 bus_register() adds a corresponding entry to /sys/bus/, while device_-register() adds entries under /sys/devices/. struct bus_type, struct device, and struct device_driver are the main data structures used respectively by buses, devices, and drivers. Take a peek inside include/linux/device.h for their definitions.
bus_register() adds a corresponding entry to /sys/bus/, while device_-register() adds entries under /sys/devices/. struct bus_type, struct device, and struct device_driver are the main data structures used respectively by buses, devices, and drivers. Take a peek inside include/linux/device.h for their definitions.
6/25/2008
2 p 114 Power management is critical on devices running on battery, such as laptops and handhelds. Linux drivers need to be aware of power states and have to transition across states in response to events such as standby, sleep, and low battery. Drivers utilize power-saving features supported by the underlying hardware when they switch to modes that consume less power. For example, the storage driver spins down the disk, whereas the video driver blanks the display.
Power management is critical on devices running on battery, such as laptops and handhelds. Linux drivers need to be aware of power states and have to transition across states in response to events such as standby, sleep, and low battery. Drivers utilize power-saving features supported by the underlying hardware when they switch to modes that consume less power. For example, the storage driver spins down the disk, whereas the video driver blanks the display.
6/25/2008
2 p 115 For a fuller understanding of how APM is implemented on x86 Linux, look at arch/x86/kernel/apm_32.c, include/linux/apm_bios.h, and include/asm-x86/mach-default/apm.h in the kernel tree. If you are curious to know how APM is implemented on BIOS-less architectures such as ARM, look at include/linux/apm-emulation.h and its users. The kernel’s ACPI implementation lives in drivers/acpi/.
For a fuller understanding of how APM is implemented on x86 Linux, look at arch/x86/kernel/apm_32.c, include/linux/apm_bios.h, and include/asm-x86/mach-default/apm.h in the kernel tree. If you are curious to know how APM is implemented on BIOS-less architectures such as ARM, look at include/linux/apm-emulation.h and its users. The kernel’s ACPI implementation lives in drivers/acpi/.
6/25/2008
2 p 121 Let’s implement a char driver to access the system CMOS. The BIOS on PC-compatible hardware (see Figure 5.1) uses the CMOS to store information such as startup options, boot order, and the system date, which you can configure via the BIOS setup menu. Our example CMOS driver lets you access the two PC CMOS banks as though they are regular files. Applications can operate on /dev/cmos/0 and /dev/cmos/1, and use I/O system calls to access data from the two banks. Because the BIOS assigns semantics to the CMOS area at bit-level granularity, the driver is capable of bit-level access. So, a read() obtains the specified number of bits and advances the internal file pointer by the number of bits read.
Let’s implement a char driver to access the system CMOS. The BIOS on PC-compatible hardware (see Figure 5.1) uses the CMOS to store information such as startup options, boot order, and the system date, which you can configure via the BIOS setup menu. Our example CMOS driver lets you access the two PC CMOS banks as though they are regular files. Applications can operate on /dev/cmos/0 and /dev/cmos/1, and use I/O system calls to access data from the two banks. Because the BIOS assigns semantics to the CMOS area at bit-level granularity, the driver is capable of bit-level access. So, a read() obtains the specified number of bits and advances the internal file pointer by the number of bits read.
6/25/2008
2 p 123 Listing 5.1CMOS Driver Initialization
#include <linux/fs.h>

/* Per-device (per-bank) structure */
struct cmos_dev {
unsigned short current_pointer; /* Current pointer within the
bank */
unsigned int size; /* Size of the bank */
int bank_number; /* CMOS bank number */
struct cdev cdev; /* The cdev structure */
char name[10]; /* Name of I/O region */
/* ... */ /* Mutexes, spinlocks, wait
queues, .. */
} *cmos_devp;
Listing 5.1CMOS Driver Initialization
#include <linux/fs.h>
#include <linux/cdev.h>

/* Per-device (per-bank) structure */
struct cmos_dev {
unsigned short current_pointer; /* Current pointer within the
bank */
unsigned int size; /* Size of the bank */
int bank_number; /* CMOS bank number */
struct cdev cdev; /* The cdev structure */
char name[10]; /* Name of I/O region */
/* ... */ /* Mutexes, spinlocks, wait
queues, .. */
} *cmos_devp;
6/25/2008
2 p 124 for (i=0; i<NUM_CMOS_BANKS; i++) {
/* Allocate memory for the per-device structure */
cmos_devp = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
if (!cmos_devp) {
printk("Bad Kmalloc\n"); return 1;
}
for (i=0; i<NUM_CMOS_BANKS; i++) {
/* Allocate memory for the per-device structure */
cmos_devp = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
if (!cmos_devp) {
printk("Bad Kmalloc\n"); return -ENOMEM;
}
6/25/2008
2 p 125 /* Connect the major/minor number to the cdev */
if (cdev_add(&cmos_devp->cdev, (dev_number + i), 1)) {
printk("Bad cdev\n");
return 1;
}

/* Send uevents to udev, so it'll create /dev nodes */
class_device_create(cmos_class, NULL, (dev_number + i),
NULL, "cmos%d", i);
}

printk("CMOS Driver Initialized.\n");
return 0;
}


/* Driver Exit */
void __exit
cmos_cleanup(void)
{
int i;

/* Remove the cdev */
cdev_del(&cmos_devp->cdev);

/* Release the major number */
unregister_chrdev_region(MAJOR(dev_number), NUM_CMOS_BANKS);

/* Release I/O region */
for (i=0; i<NUM_CMOS_BANKS; i++) {
class_device_destroy(cmos_class, MKDEV(MAJOR(dev_number), i));
release_region(addrports[i], 2);
}
/* Connect the major/minor number to the cdev */
if (cdev_add(&cmos_devp->cdev, (cmos_dev_number + i), 1)) {
printk("Bad cdev\n");
return 1;
}

/* Send uevents to udev, so it'll create /dev nodes */
class_device_create(cmos_class, NULL, (cmos_dev_number + i),
NULL, "cmos%d", i);
}

printk("CMOS Driver Initialized.\n");
return 0;
}


/* Driver Exit */
void __exit
cmos_cleanup(void)
{
int i;

/* Remove the cdev */
cdev_del(&cmos_devp->cdev);

/* Release the major number */
unregister_chrdev_region(cmos_dev_number), NUM_CMOS_BANKS);

/* Release I/O region */
for (i=0; i<NUM_CMOS_BANKS; i++) {
class_device_destroy(cmos_class, (cmos_dev_number) + i))
release_region(addrports[i], 2);
}
6/25/2008
2 p 126 First, cmos_init() invokes alloc_chrdev_region() to dynamically request an unused major number. dev_number contains the allotted major number if the call is successful. The second and third arguments to alloc_chrdev_region() specify the start minor number and the number of supported minor devices, respectively. The last argument is the device name used to identify the CMOS in /proc/devices:
First, cmos_init() invokes alloc_chrdev_region() to dynamically request an unused major number. cmos_dev_number contains the allotted device number if the call is successful. The second and third arguments to alloc_chrdev_region() specify the start minor number and the number of supported minor devices, respectively. The last argument is the device name used to identify the CMOS in /proc/devices: 6/25/2008
2 p 127 Device drivers that need to operate on a range of I/O addresses stake claim to the addresses via a call to request_region(). This regulatory mechanism ensures that requests by others for the same region fail until the occupant releases it via a call to release_region(). request_region() is commonly invoked by I/O bus drivers such as PCI and ISA to mark ownership of on-card memory in the processor’s address space (more on this in Chapter 10, “Peripheral Component Interconnect”). cmos_init() requests access to the I/O region of each CMOS bank by calling request_region(). The last argument to request_region() is an identifier used by /proc/ioports, so you will see this if you peek at that file:
Device drivers that need to operate on a range of I/O addresses stake claim to the addresses via a call to request_region(). This regulatory mechanism ensures that requests by others for the same region fail until the occupant releases it via a call to release_region(). request_region() is commonly invoked by I/O bus drivers such as PCI and ISA to mark ownership of on-card memory in the processor’s address space (more on this in Chapter 10, “Peripheral Component Interconnect”). cmos_init() requests access to the I/O region of each CMOS bank by calling request_region(). The last argument to request_region() is an identifier used by /proc/ioports, so you will see this if you peek at that file:
6/25/2008
2 p 140 You may supply a bunch of file descriptors to select() and ask it to keep an eye on them until there is a change in the associated data state. You may also request a timeout to override data availability. If you ask for a timeout of NULL, select() blocks forever. Refer to the man or info pages of select() for detailed documentation. The call to select() in the preceding snippet induces the X server to poll for data from a connected mouse within a timeout.
You may supply a bunch of file descriptors to select() and ask it to keep an eye on them until there is a change in the associated data state. You may also request a timeout to override data availability. If you ask for a timeout of NULL, select() blocks forever. Refer to the man or info pages of select() for detailed documentation. The call to select() in the preceding snippet induces the X server to poll for data from a connected mouse within a timeout.
6/25/2008
2 p 141 Most I/O system calls are POSIX-compliant and are not Linux-specific (programs such as X Windows after all, run on many UNIX flavors, not just on Linux), but the internal driver methods are operating system-specific. On Linux, the poll() driver method is the pillar under the select() system call. In the previous X server scenario, the mouse driver’s poll() method looks like this:
Most I/O system calls are POSIX-compliant and are not Linux-specific (programs such as X Windows after all, run on many UNIX flavors, not just on Linux), but the internal driver methods are specific to the operating system. On Linux, the poll() driver method is the pillar under the select() system call. In the previous X server scenario, the mouse driver’s poll() method looks like this:
6/25/2008
2 p 150 unregister_chrdev_region(MAJOR(dev_number), 1);
class_device_destroy(led_class, MKDEV(MAJOR(dev_number), 0));
class_destroy(led_class);
return;
}

module_init(led_init);
module_exit(led_cleanup);

MODULE_LICENSE("GPL");
led_init() is similar to cmos_init() developed in Listing 5.1, but for a couple of things:
1. As you saw in Chapter 4, the new device model distinguishes between drivers and devices. led_init() registers the LED driver with parport via a call to -parport_register_driver().When the kernel finds the LED board during led_attach(), it registers the device by invoking parport_register_device().
2. led_init() creates the device node /dev/led, which you can use to control the state of individual LEDs.
unregister_chrdev_region(dev_number, 1);
class_device_destroy(led_class,dev_number);
class_destroy(led_class);
return;
}

module_init(led_init);
module_exit(led_cleanup);

MODULE_LICENSE("GPL");
led_init() is similar to cmos_init() developed in Listing 5.1, but for a couple of things:
1. As you saw in Chapter 4, the new device model distinguishes between drivers and devices. led_init() registers the LED driver with parport via a call to -parport_register_driver().When the kernel finds the LED board during led_attach(), it registers the device by invoking parport_register_device().
2. led_init() creates the device node /dev/led, which you can use to control the state of individual LEDs.
6/25/2008
2 p 154 /* Driver Initialization */
int __init
led_init(void)
{
struct class_device *c_d;

/* Create the pardevice class - /sys/class/pardevice */
led_class = class_create(THIS_MODULE, "pardevice");
if (IS_ERR(led_class)) printk("Bad class create\n");
int __init
led_init(void)
{
struct class_device *c_d;
If (alloc_chrdev_region (&dev_number, 0, 1, DEVICE_NAME
< 0) {
printk(KERN_DEBUG “Can’t register new device\n”);
return -1

/* Create the pardevice class - /sys/class/pardevice */
led_class = class_create(THIS_MODULE, "pardevice");
if (IS_ERR(led_class)) printk("Bad class create\n");
6/25/2008
2 p 155 /* Destroy class device corresponding to
/sys/class/pardevice/led/ */
class_device_destroy(led_class, MKDEV(MAJOR(dev_number), 0));
/* Destroy class device corresponding to
/sys/class/pardevice/led/ */
class_device_destroy(led_class, dev_number);
6/25/2008
2 p 157 in Documentation/rtc.txt, is a set of standard ioctls that conforming applications such as hwclock leverage by operating on /dev/rtc. The API also specifies attributes in sysfs (/sys/class/rtc/) and procfs (/proc/driver/rtc). The RTC API guarantees that user space tools are independent of the underlying platform and the RTC chip. The bottom-layer RTC driver is bus-specific. The embedded device discussed in the section “Device Example: Real Time Clock” in Chapter 8, “The Inter-Integrated Circuit Protocol,” has an RTC chip connected to the I2C bus, which is driven by an I2C client driver.
The kernel has a dedicated RTC subsystem that provides the top-layer char driver and a core infrastructure that bottom-layer RTC drivers can use to tie in with the top layer. The main components of this infrastructure are the rtc_class_ops structure and the registration functions, rtc_device_[register|unregister](). Bottom-layer RTC drivers scattered under different bus-specific directories are being unified with this subsystem under drivers/rtc/.
The RTC subsystem allows the possibility that a system can have more than one RTC. It does this by exporting multiple interfaces, /dev/rtcN and /sys/class/rtc/rtcN, where N is the number of RTCs on your system. Some embedded systems, for example, have two RTCs: one built in to the microcontroller to support sophisticated operations such as periodic interrupt generation, and another no-frills low-power battery-backed external RTC for timekeeping. Because RTC-aware applications operate over /dev/rtc, set up a symbolic link so that one of the created /dev/rtcX nodes can be accessed as /dev/rtc.
To enable the RTC subsystem, turn on CONFIG_RTC_CLASS during kernel configuration.
The Legacy PC RTC Driver
On PC systems, you have the option of bypassing the RTC subsystem by using the legacy RTC driver, drivers/char/rtc.c. This driver provides top and bottom layers for the RTC on PC--compatible systems and exports /dev/rtc and /proc/driver/rtc to user applications. To enable this driver, turn on CONFIG_RTC during kernel configuration.
Pseudo Char Drivers
Several commonly used kernel facilities are not connected with any physical hardware, and these are elegantly implemented as char devices. The null sink, the perpetual zero
in Documentation/rtc.txt, is a set of standard ioctls that conforming applications such as hwclock leverage by operating on /dev/rtc. The API also specifies attributes in sysfs (/sys/class/rtc/) and procfs (/proc/driver/rtc). The RTC API guarantees that user space tools are independent of the underlying platform and the RTC chip. The bottom-layer RTC driver is bus-specific. The embedded device discussed in the section “Device Example: Real Time Clock” in Chapter 8, “The Inter-Integrated Circuit Protocol,” has an RTC chip connected to the I2C bus, which is driven by an I2C client driver.
The kernel has a dedicated RTC subsystem that provides the top-layer char driver and a core infrastructure that bottom-layer RTC drivers can use to tie in with the top layer. The main components of this infrastructure are the rtc_class_ops structure and the registration functions, rtc_device_[register|unregister](). Bottom-layer RTC drivers scattered under different bus-specific directories are being unified with this subsystem under drivers/rtc/.
The RTC subsystem allows the possibility that a system can have more than one RTC. It does this by exporting multiple interfaces, /dev/rtcN and /sys/class/rtc/rtcN, where N is the number of RTCs on your system. Some embedded systems, for example, have two RTCs: one built in to the microcontroller to support sophisticated operations such as periodic interrupt generation, and another no-frills low-power battery-backed external RTC for timekeeping. Because RTC-aware applications operate over /dev/rtc, set up a symbolic link so that one of the created /dev/rtcX nodes can be accessed as /dev/rtc.
To enable the RTC subsystem, turn on CONFIG_RTC_CLASS during kernel configuration.
The Legacy PC RTC Driver
On PC systems, you have the option of bypassing the RTC subsystem by using the legacy RTC driver, drivers/char/rtc.c. This driver provides top and bottom layers for the RTC on PC--compatible systems and exports /dev/rtc and /proc/driver/rtc to user applications. To enable this driver, turn on CONFIG_RTC during kernel configuration.
Pseudo Char Drivers
Several commonly used kernel facilities are not connected with any physical hardware, but are elegantly implemented as char devices. The null sink, the perpetual zero
6/25/2008
2 p 158 Instead, it gathers “environmental noise” (interval between interrupts, key clicks, and so on) for maintaining a reservoir of disorder (called an entropy pool) that seeds the random stream. To see the kernel’s input subsystem (discussed in Chapter 7) contributing to the entropy pool when it detects a keyboard press or mouse movement, look at input_event() defined in drivers/input/input.c:
Instead, it gathers “environmental noise” (interval between interrupts, key clicks, and so on) for maintaining a reservoir of disorder (called an entropy pool) that seeds the random stream. To see the kernel’s input subsystem (discussed in Chapter 7) contributing to the entropy pool when it detects a keyboard press or mouse movement, look at input_event() defined in drivers/input/input.c:
6/25/2008
2 p 159 To see how the core interrupt handling layer contributes inter-interrupt periods to the entropy pool, look at handle_IRQ_event() defined in kernel/irq/handle.c:
irqreturn_t handle_IRQ_event(unsigned int irq,
struct irqaction *action)
{
/* ... */
if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq); /* Contribute to entropy pool */
/* ... */
}
The generation of strongly random numbers depends on the size of the entropy pool:
bash> od –x /dev/random
0000000 7331 9028 7c89 4791 7f64 3deb 86b3 7564
0000020 ebb9 e806 221a b8f9 af12 cb30 9a0e cc28
0000040 68d8 0bbf 68a4 0898 528e 1557 d8b3 57ec
0000060 b01d 8714 b1e1 19b9 0a86 9f60 646c c269
The output stops after a few lines, signaling that the entropy pool is exhausted. To replenish the entropy pool and restart the random stream, jab the keyboard several times after switching to an unused terminal or push the mouse around the screen.
A dump of /dev/urandom, however, produces a continuous pseudo random stream that never stops.
/dev/mem and /dev/kmem are classic pseudo char devices that are tools that let you peek inside system memory. These char nodes export raw interfaces connected to physical memory and kernel virtual memory, respectively. To manipulate system memory, you may mmap() these nodes and operate on the returned regions. As an exercise, change the hostname of your system by accessing /dev/mem.
All the char devices discussed in this section (null, zero, random, urandom, mem, and kmem) have different minor numbers but the same statically assigned major number, 1. Look at drivers/char/mem.c and drivers/char/random.c for their implementation. Two other pseudo drivers belong to the same major number family: /dev/full, which emulates an always full device; and /dev/port, which peeks at system I/O ports. We use the latter in Chapter 19.
To see how the core interrupt handling layer contributes inter-interrupt periods to the entropy pool, look at handle_IRQ_event() defined in kernel/irq/handle.c:
irqreturn_t handle_IRQ_event(unsigned int irq,
struct irqaction *action)
{
/* ... */
if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq); /* Contribute to entropy pool */
/* ... */
}
The generation of strongly random numbers depends on the size of the entropy pool:
bash> od –x /dev/random
0000000 7331 9028 7c89 4791 7f64 3deb 86b3 7564
0000020 ebb9 e806 221a b8f9 af12 cb30 9a0e cc28
0000040 68d8 0bbf 68a4 0898 528e 1557 d8b3 57ec
0000060 b01d 8714 b1e1 19b9 0a86 9f60 646c c269
The output stops after a few lines, signaling that the entropy pool is exhausted. To replenish the entropy pool and restart the random stream, jab the keyboard several times after switching to an unused terminal or push the mouse around the screen.
A dump of /dev/urandom, however, produces a continuous pseudo random stream that never stops.
/dev/mem and /dev/kmem are classic pseudo char devices that are tools that let you peek inside system memory. These char nodes export raw interfaces connected to physical memory and kernel virtual memory, respectively. To manipulate system memory, you may mmap() these nodes and operate on the returned regions. As an exercise, change the hostname of your system by accessing /dev/mem.
All the char devices discussed in this section (null, zero, random, urandom, mem, and kmem) have different minor numbers but the same statically assigned major number, 1. Look at drivers/char/mem.c and drivers/char/random.c for their implementation. Two other pseudo drivers belong to the same major number family: /dev/full, which emulates an always full device; and /dev/port, which peeks at system I/O ports. We use the latter in Chapter 19.
6/25/2008
2 p 165 The driver’s write() method pulses the watchdog’s input pin whenever application software writes to the associated device node. To aid manufacturing and field diagnostics, the watchdog is wired such that it can be disabled by wiggling a processor GPIO pin.
The driver’s write() method pulses the watchdog’s input pin whenever application software writes to the associated device node. To aid manufacturing and field diagnostics, the watchdog may be wired such that it can be disabled by wiggling a processor GPIO pin.
6/25/2008
2 p 166 A related support in 2.6 kernels is the sensing of soft lockups, which are instances when scheduling does not occur for 10 or more seconds. A kernel thread watchdog/N, where N is the CPU number, touches a per-CPU timestamp every second. If the thread doesn’t touch the timestamp for more than 10 seconds, the system is deemed to have locked up. Soft lockup detection (implemented in kernel/softlockup.c) will aid us while debugging a kernel crash in the section “Kdump” in Chapter 21, “Debugging Device Drivers.”
There are several more misc drivers in the kernel. The Qtronix infrared keyboard driver, drivers/char/qtronix.c, is another example of a char driver that has a misc form factor. Do a grep on misc_register() in the drivers/char/ directory to find other misc device drivers present in the kernel.
Character Caveats
Driver methods, and hence the associated system calls issued by user applications, may fail or partially succeed. Your application has to factor this in to avoid unpleasant surprises. Let’s look at some common pitfalls:
A related support in 2.6 kernels is the sensing of soft lockups, which are instances when scheduling does not occur for 10 or more seconds. A kernel thread watchdog/N, where N is the CPU number, touches a per-CPU timestamp every second. If the thread doesn’t touch the timestamp for more than 10 seconds, the system is deemed to have locked up. Soft lockup detection (implemented in kernel/softlockup.c) will aid us while debugging a kernel crash in the section “Kdump” in Chapter 21, “Debugging Device Drivers.”
There are several more misc drivers in the kernel. The Qtronix infrared keyboard driver, drivers/char/qtronix.c, is another example of a char driver that has a misc form factor. Do a grep on misc_register() in the drivers/char/ directory to find other misc device drivers present in the kernel.
Character Caveats
Driver methods, and hence the associated system calls issued by user applications, may fail or partially succeed. Your application has to factor this in to avoid unpleasant surprises. Let’s look at some common pitfalls:
6/25/2008
2 p 167 • Input drivers are responsible for devices such as keyboards, mice, and joysticks. They live in a separate source directory, drivers/input/ and, hence, get a distinct chapter, Chapter 7.
• Input drivers are responsible for devices such as keyboards, mice, and joysticks. They live in a separate source directory, drivers/input/, and hence get a distinct chapter, Chapter 7.
6/25/2008
2 p 178 There are two important steps that a UART driver has to do to tie itself with the kernel:
There are two important steps that a UART driver has to take to tie itself with the kernel:
6/25/2008
2 p 181 2. A platform driver. The platform driver registers itself into the platform using platform_driver_register(). The platform_driver structure, also de-fined in include/linux/platform_device.h, represents a platform driver:
2. A platform driver. The platform driver registers itself into the platform using platform_driver_register(). The platform_driver structure, also de-fined in include/linux/platform_device.h, represents a platform driver:
6/25/2008
2 p 194 • To work with a system console on a Linux desktop, you need the services of virtual terminals (VTs) if you are in text mode or pseudo terminals (PTYs) if you are in graphics mode. VTs and PTYs are implemented as tty drivers and live in drivers/char/vt.c and drivers/char/pty.c, respectively.
• To work with a system console on a Linux desktop, you need the services of virtual terminals (VTs) if you are in text mode or pseudo terminals (PTYs) if you are in graphics mode. VTs and PTYs are implemented as tty drivers and live in drivers/char/vt.c and drivers/char/pty.c, respectively.
6/25/2008
2 p 205 The serial core resides in drivers/serial/, but tty implementations and low-level drivers are scattered across the source tree. The driver files referred to in Figure 6.3, for example, live in four different directories: drivers/serial/, drivers/char/, drivers/usb/serial/, and drivers/net/irda/. The drivers/serial/ directory, which now also contains UART drivers, didn’t exist in the 2.4 kernel; UART-specific code used to be dispersed between drivers/char/ and arch/your-arch/ directories. The present code partitioning is more logical because UART drivers are not the only folks that access the serial layer—devices such as USB-to-serial converters and IrDA dongles also need to talk to the serial core.
The serial core resides in drivers/serial/, but tty implementations and low-level drivers are scattered across the source tree. The driver files referred to in Figure 6.3, for example, live in four different directories: drivers/serial/, drivers/char/, drivers/usb/serial/, and drivers/net/irda/. The drivers/serial/ directory, which now also contains UART drivers, didn’t exist in the 2.4 kernel; UART-specific code used to be dispersed between drivers/char/ and arch/your-arch/ directories. The present code partitioning is more logical because UART drivers are not the only folks that access the serial layer—devices such as USB-to-serial converters and IrDA dongles also need to talk to the serial core.
6/25/2008
2 p 208 Figure 7.1 illustrates the operation of the input subsystem. The subsystem contains two classes of drivers that work in tandem: event drivers and device drivers. Event drivers are responsible for interfacing with applications, whereas device drivers are responsible for low-level communication with input devices. The mouse event generator, mousedev, is an example of the former, and the PS/2 mouse driver is an example of the latter. Both event drivers and device drivers can avail the services of an efficient, bug-free, reusable core, which lies at the heart of the input subsystem.
Figure 7.1 illustrates the operation of the input subsystem. The subsystem contains two classes of drivers that work in tandem: event drivers and device drivers. Event drivers are responsible for interfacing with applications, whereas device drivers are responsible for low-level communication with input devices. The mouse event generator, mousedev, is an example of the former, and the PS/2 mouse driver is an example of the latter. Both event drivers and device drivers can avail the services of an efficient, bug-free, reusable core, which lies at the heart of the input subsystem.
6/25/2008
2 p 210 Listing 7.1 contains coord.c, which continuously generates random X and Y coordinates. Mice, unlike joysticks or touch screens, produce relative coordinates, so that is what coord.c does. The vms driver is shown in Listing 7.2.
Listing 7.1 contains coord.c, which continuously generates random X and Y coordinates. Mice, unlike joysticks or touch screens, produce relative coordinates, so that is what coord.c does. The vms driver is shown in Listing 7.2.
6/25/2008
2 p 211 figure font change fixed 6/25/2008
2 p 212 struct input_dev *vms_input_dev; /* Representation of an input device */
static struct platform_device *vms_dev; /* Device structure */

/* Sysfs method to input simulated
coordinates to the virtual
mouse driver */
static ssize_t
write_vms(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
struct input_dev *vms_input_dev; /* Representation of an input device */
static struct platform_device *vms_dev; /* Device structure */

/* Sysfs method to input simulated
coordinates to the virtual
mouse driver */
static ssize_t
write_vms(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
6/25/2008
2 p 213 vms_dev = platform_device_register_simple("vms", -1, NULL, 0);
if (IS_ERR(vms_dev)) {
PTR_ERR(vms_dev);
printk("vms_init: error\n");
}

/* Create a sysfs node to read simulated coordinates */
sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);

/* Allocate an input device data structure */
vms_input_dev = input_allocate_device();
if (!vms_input_dev) {
printk("Bad input_alloc_device()\n");
vms_dev = platform_device_register_simple("vms", -1, NULL, 0);
If (IS_ERR(vms_dev)){
printk (“vms_init: error\n”);
return PTR_ERR(vms_dev);
}
}

/* Create a sysfs node to read simulated coordinates */
sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);

/* Allocate an input device data structure */
vms_input_dev = input_allocate_device();
if (!vms_input_dev) {
printk("Bad input_allocate_device()\n"); return -ENOMEM
6/25/2008
2 p 215 The first statement generates a REL_X event or a relative device movement in the X direction. The second produces a REL_Y event or a relative movement in the Y direction. input_sync() indicates that this event is complete, so the input subsystem collects these two events into a single evdev packet and sends it out of the door through /dev/input/eventX, where X is the interface number assigned to the vms driver. An application reading this file will receive event packets in the input_event format described earlier. To request gpm to attach to this event interface and accordingly chase the cursor around your screen, do this:
The first statement generates a REL_X event or a relative device movement in the X direction. The second produces a REL_Y event or a relative movement in the Y direction. input_sync() indicates that this event is complete, so the input subsystem collects these two events into a single evdev packet and sends it out of the door through /dev/input/eventX, where X is the interface number assigned to the vms driver. An application reading this file will receive event packets in the input_event format described earlier. To request gpm to attach to this event interface and accordingly chase the cursor around your screen, do this:
6/25/2008
2 p 220 fix font in figure fixed 6/25/2008
2 p 222 + {
+ /* Allocate input device structure */
+ roller_mouse->dev = input_allocate_device();
+
+ /* Can generate a click and a relative movement */
+ roller_mouse->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);

+ /* Can move only in the Y-axis */
+ roller_mouse->dev->relbit[0] = BIT(REL_Y);
+
+ /* My click should be construed as the left button
+ press of a mouse */
+ roller_mouse->dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT);

+ roller_mouse->dev->name = "roll";
+
+ /* For entries in /sys/class/input/inputX/id/ */
+ roller_mouse->dev->id.bustype = ROLLER_BUS;
+ roller_mouse->dev->id.vendor = ROLLER_VENDOR;
+ roller_mouse->dev->id.product = ROLLER_PROD;
+ roller_mouse->dev->id.version = ROLLER_VER;

+ /* Register with the input subsystem */
+ input_register_device(roller_mouse->dev);
+}
+ {
+ /* Allocate input device structure */
+ roller_mouse->dev = input_allocate_device();
+
+ /* Can generate a click and a relative movement */
+ roller_mouse->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);

+ /* Can move only in the Y-axis */
+ roller_mouse->dev->relbit[0] = BIT(REL_Y);
+
+ /* My click should be construed as the left button
+ press of a mouse */
+ roller_mouse->dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT);

+ roller_mouse->dev->name = "roll";
+
+ /* For entries in /sys/class/input/inputX/id/ */
+ roller_mouse->dev->id.bustype = ROLLER_BUS;
+ roller_mouse->dev->id.vendor = ROLLER_VENDOR;
+ roller_mouse->dev->id.product = ROLLER_PROD;
+ roller_mouse->dev->id.version = ROLLER_VER;

+ /* Register with the input subsystem */
+ input_register_device(roller_mouse->dev);
+ }
6/25/2008
2 p 223 Unlike a regular mouse, a trackpoint offers more movement control. You can command the trackpoint controller to change properties such as sensitivity and inertia. The kernel has a special driver, drivers/input/mouse/trackpoint.c, to create and manage associated sysfs nodes. For the full set of track point configuration options, look under /sys/devices/platform/i8042/serioX/serioY/.
Unlike a regular mouse, a trackpoint offers more movement control. You can command the trackpoint controller to change properties such as sensitivity and inertia. The kernel has a special driver, drivers/input/mouse/trackpoint.c, to create and manage associated sysfs nodes. For the full set of track point configuration options, look under /sys/devices/platform/i8042/serioX/serioY/.
6/25/2008
2 p 231 This translates to a (type, code, value) tuple of (0x0, 0x0, 0x0) and completes each input event.
Looking at the Sources
Most input event drivers are present in the drivers/input/ directory. The keyboard event driver, however, lives in drivers/char/keyboard.c, because it’s connected to virtual terminals and not to device nodes under /dev/input/.
This translates to a (type, code, value) tuple of (0x0, 0x0, 0x0) and completes each input event.
Looking at the Sources
Most input event drivers are present in the drivers/input/ directory. The keyboard event driver, however, lives in drivers/char/keyboard.c, because it’s connected to virtual terminals and not to device nodes under /dev/input/.
6/25/2008
2 p 235 I2C and its subset SMBus are 2-wire interfaces originally developed by Philips and Intel, respectively. The two wires are clock and bidirectional data, and the corresponding lines are called Serial CLock (SCL) and Serial DAta (SDA). Because the I2C bus needs only a pair of wires, it consumes less space on the circuit board. However, the supported bandwidths are also low. I2C allows up to 100Kbps in the standard mode and 400Kbps in a fast mode. (SMBus supports only up to 100Kbps, however.) The bus is thus suitable only for slow peripherals. Even though I2C supports bidirectional exchange, the communication is half duplex because there is only a single data wire.
I2C and its subset SMBus are 2-wire interfaces originally developed by Philips and Intel, respectively. The two wires are clock and bidirectional data, and the corresponding lines are called Serial CLock (SCL) and Serial DAta (SDA). Because the I2C bus needs only a pair of wires, it consumes less space on the circuit board. However, the supported bandwidths are also low. I2C allows up to 100Kbps in the standard mode and 400Kbps in a fast mode. (SMBus supports only up to 100Kbps, however.) The bus is thus suitable only for slow peripherals. Even though I2C supports bidirectional exchange, the communication is half duplex because there is only a single data wire.
6/25/2008
2 p 236 • Device drivers for I2C host adapters. They fall in the realm of bus drivers and usually consist of an adapter driver and an algorithm driver. The former uses the latter to talk to the I2C bus.
• Device drivers for I2C host adapters. They fall in the realm of bus drivers and usually consist of an adapter (or controller) driver and an algorithm driver. The former uses the latter to talk to the I2C bus. 6/25/2008
2 p 241 Listing 8.3Opening the EEPROM Driver
int
eep_open(struct inode *inode, struct file *file)
{
/* The EEPROM bank to be opened */
n = MINOR(file->f_dentry->d_inode->i_rdev);

file->private_data = (struct ee_bank *)ee_bank_list[n];

/* Initialize the fields in ee_bank_list[n] such as
size, slave address, and the current file pointer */
/* ... */
}
Listing 8.3Opening the EEPROM Driver
int
eep_open(struct inode *inode, struct file *file)
{
/* The EEPROM bank to be opened */
n = MINOR(file->f_dentry->d_inode->i_rdev);

file->private_data = (struct ee_bank *)ee_bank_list[n];

/* Initialize the fields in ee_bank_list[n] such as
size, slave address, and the current file pointer */
/* ... */
}
6/25/2008
2 p 242 2. When the core calls the driver’s probe() method signifying the presence of a host adapter, it, in turn, invokes i2c_probe() with arguments specifying the addresses of the slave devices that the driver is responsible for and an associated attach() routine.
Listing 8.4 implements eep_probe(), the probe() method of the EEPROM driver. normal_i2c specifies the EEPROM bank addresses and is populated as part of the i2c_client_address_data structure. Additional fields in this structure can be used to request finer addressing control. You can ask the I2C core to ignore a range of addresses using the ignore field. Or you may use the probe field to specify (adapter, slave address) pairs if you want to bind a slave address to a particular host adapter. This will be useful, for example, if your processor supports two I2C host adapters, and you have an EEPROM on bus 1 and a temperature sensor on bus 2, both answering to the same slave address.
3. The host controller walks the bus looking for the slave devices specified in Step 2. To do this, it generates a bus transaction such as S SLAVE_ADDR Wr, where S is the start bit, SLAVE_ADDR is the associated 7-bit slave address as specified in the device’s datasheet, and Wr is the write command, as described in the section “Bus Transactions.” If a working slave device exists on the bus, it’ll respond by sending an acknowledgment bit ([A]).
4. If the host adapter detects a slave in Step 3, the I2C core invokes the attach() routine supplied via the third argument to i2c_probe() in Step 2. For the EEPROM driver, this routine is eep_attach(), which registers a per-device client data structure, as shown in Listing 8.5. If your device expects an initial programming sequence (for example, registers on an I2C Digital Visual Interface transmitter chip have to be initialized before the chip can start functioning), perform those operations in this routine.
2. When the core calls the driver’s probe() method signifying the presence of a host controller, it, in turn, invokes i2c_probe() with arguments specifying the addresses of the slave devices that the driver is responsible for and an associated attach() routine.
Listing 8.4 implements eep_probe(), the probe() method of the EEPROM driver. normal_i2c specifies the EEPROM bank addresses and is populated as part of the i2c_client_address_data structure. Additional fields in this structure can be used to request finer addressing control. You can ask the I2C core to ignore a range of addresses using the ignore field. Or you may use the probe field to specify (adapter, slave address) pairs if you want to bind a slave address to a particular host adapter. This will be useful, for example, if your processor supports two I2C host controllers, and you have an EEPROM on bus 1 and a temperature sensor on bus 2, both answering to the same slave address.
3. The host controller walks the bus looking for the slave devices specified in Step 2. To do this, it generates a bus transaction such as S SLAVE_ADDR Wr, where S is the start bit, SLAVE_ADDR is the associated 7-bit slave address as specified in the device’s datasheet, and Wr is the write command, as described in the section “Bus Transactions.” If a working slave device exists on the bus, it’ll respond by sending an acknowledgment bit ([A]).
4. If the host controller detects a slave in Step 3, the I2C core invokes the attach() routine supplied via the third argument to i2c_probe() in Step 2. For the EEPROM driver, this routine is eep_attach(), which registers a per-device client data structure, as shown in Listing 8.5. If your device expects an initial programming sequence (for example, registers on an I2C Digital Visual Interface transmitter chip have to be initialized before the chip can start functioning), perform those operations in this routine.
6/25/2008
2 p 252 1. Registers probe() and remove() methods with the SPI core. Optionally registers suspend() and resume() methods:
#include <linux/spi/spi.h>

static struct spi_driver myspi_driver = {
.driver = {
.name = "myspi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = myspidevice_probe,
.remove = __devexit_p(myspidevice_remove),
}

spi_register_driver(&myspi_driver);
The SPI core creates an spi_device structure corresponding to this device and passes this as an argument when it invokes the registered driver methods.
2. Exchanges messages with the SPI device using access functions such as spi_sync()and spi_async(). The former waits for the operation to complete, whereas the latter asynchronously triggers invocation of a registered callback routine when message transfer completes. These data access routines are invoked from suitable places such as the SPI interrupt handler, a sysfs method, or a timer handler. The following code snippet illustrates SPI message submission:
#include <linux/spi/spi.h>

struct spi_device *spi; /* Representation of a
SPI device */
1. Registers probe() and remove() methods with the SPI core. Optionally registers suspend() and resume() methods:
#include <linux/spi/spi.h>

static struct spi_driver myspi_driver = {
.driver = {
.name = "myspi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = myspidevice_probe,
.remove = __devexit_p(myspidevice_remove),
};

spi_register_driver(&myspi_driver);
The SPI core creates an spi_device structure corresponding to this device and passes this as an argument when it invokes the registered driver methods.
2. Exchanges messages with the SPI device using access functions such as spi_sync()and spi_async(). The former waits for the operation to complete, whereas the latter asynchronously triggers invocation of a registered callback routine when message transfer completes. These data access routines are invoked from suitable places such as the SPI interrupt handler, a sysfs method, or a timer handler. The following code snippet illustrates SPI message submission:
#include <linux/spi/spi.h>

struct spi_device *spi; /* Representation of an
SPI device */
6/25/2008
2 p 253 4. The callback function in turn, reports touch coordinates and clicks via the input event interface, /dev/input/eventX, using input_report_abs() and input_report_key(), as discussed in Chapter 7. Applications such as X Windows and gpm seamlessly work with the event interface and respond to touch input.
4. The callback function in turn, reports touch coordinates and clicks via the input event interface, /dev/input/eventX, using input_report_abs() and input_report_key(), as discussed in Chapter 7. Applications such as X Windows and gpm seamlessly work with the event interface and respond to touch input.
6/25/2008
2 p 254 In the embedded world, you may come across solutions where the processor uses a companion chip that integrates various functions. An example is the Freescale MC13783 Power Management and Audio Component (PMAC) used in tandem with the ARM9-based i.MX27 controller. The PMAC integrates an RTC, a battery charger, a touch-screen interface, an ADC module, and an audio codec. The processor and the PMAC communicate over SPI. The SPI bus does not contain an interrupt line, so the PMAC has the capability to externally interrupt the processor using a GPIO pin configured for this purpose.
In the embedded world, you may come across solutions where the processor uses a companion chip that integrates various functions. An example is the Freescale MC13783 Power Management and Audio Component (PMAC) used in tandem with the ARM9-based i.MX27 processor. The PMAC integrates an RTC, a battery charger, a touch-screen interface, an ADC module, and an audio codec. The processor and the PMAC communicate over SPI. The SPI bus does not contain an interrupt line, so the PMAC has the capability to externally interrupt the processor using a GPIO pin configured for this purpose. 6/25/2008
2 p 255 The drivers/w1/ directory contains kernel support for the w1 protocol. Drivers for the host controller side of the w1 interface live in drivers/w1/masters/, and drivers for w1 slaves reside in drivers/w1/slaves/.
The drivers/w1/ directory contains kernel support for the w1 protocol. Drivers for the host controller side of the w1 interface live in drivers/w1/masters/, and drivers for w1 slaves reside in drivers/w1/slaves/.
6/25/2008
2 p 260 The Old Linux-PCMCIA Subsystem
The Linux-PCMCIA subsystem has recently undergone an overhaul. To get PCMCIA working with 2.6.13 and newer kernels, you need the pcmciautils package (http://kernel.org/pub/linux/utils/kernel/pcmcia/howto.html), which obsoletes the pcmcia-cs package (http://pcmcia-cs.sourceforge.net) used with earlier kernels. Internal kernel programming interfaces and data structures have also changed. Earlier kernels relied on a user space daemon called cardmgr to support hotplugging, but the new PCMCIA implementation handles hotplug using udev, just as other bus subsystems do. So with new setups, you don’t need cardmgr and should make sure that it is not started. There is a migration guide at http://kernel.org/pub/linux/utils/kernel/pcmcia/cardmgr-to-pcmciautils.html.
The Old Linux-PCMCIA Subsystem
The Linux-PCMCIA subsystem has recently undergone an overhaul. To get PCMCIA working with 2.6.13 and newer kernels, you need the pcmciautils package (http://kernel.org/pub/linux/utils/kernel/pcmcia/howto.html), which obsoletes the pcmcia-cs package (http://pcmcia-cs.sourceforge.net) used with earlier kernels. Internal kernel programming interfaces and data structures have also changed. Earlier kernels relied on a user space daemon called cardmgr to support hotplugging, but the new PCMCIA implementation handles hotplug using udev, just as other bus subsystems do. So with new setups, you don’t need cardmgr and should make sure that it is not started. There is a migration guide at http://kernel.org/pub/linux/utils/kernel/pcmcia/cardmgr-to-pcmciautils.html.
6/25/2008
2 p 266 5. The CIS contains configuration table entries for each configuration that the card supports. cistpl_cftable_entry_t, defined in include/pcmcia/cistpl.h, holds such an entry:
typedef struct cistpl_cftable_entry_t {
/* ... */
cistpl_power_t vcc, vpp1, vpp2; /* Voltage level */
cistpl_io_t io; /* I/O attributes */
cistpl_irq_t irq; /* IRQ settings */
cistpl_mem_t mem; /* Memory window */
/* ... */
};
6. cisparse_t, also defined in include/pcmcia/cistpl.h, holds a tuple parsed by the PCMCIA core:
5. The CIS contains configuration table entries for each configuration that the card supports. cistpl_cftable_entry_t, defined in include/pcmcia/cistpl.h, holds such an entry:
typedef struct cistpl_cftable_entry_t {
/* ... */
cistpl_power_t vcc, vpp1, vpp2; /* Voltage level */
cistpl_io_t io; /* I/O attributes */
cistpl_irq_t irq; /* IRQ settings */
cistpl_mem_t mem; /* Memory window */
/* ... */
};
6. cisparse_t, also defined in include/pcmcia/cistpl.h, holds a tuple parsed by the PCMCIA core:
6/25/2008
2 p 268 Listing 9.2 shows the routine that configures the generic device driver (XX) with resource information such as I/O and memory window base addresses. After this step, data flow to and from the PCMCIA card passes through XX and is transparent to the rest of the layers. Any interrupts generated by the PCMCIA card, such as those related to data reception or transmit completion for network cards, are handled by the interrupt handler that is part of XX. Listing 9.2 is loosely based on drivers/net/-wireless/ airo_cs.c, the client driver for the Cisco Aironet 4500 and 4800 series of PCMCIA WiFi cards. The listing uses the services of the PCMCIA core to do the following:
Listing 9.2 shows the routine that configures the generic device driver (XX) with resource information such as I/O and memory window base addresses. After this step, data flow to and from the PCMCIA card passes through XX and is transparent to the rest of the layers. Any interrupts generated by the PCMCIA card, such as those related to data reception or transmit completion for network cards, are handled by the interrupt handler that is part of XX. Listing 9.2 is loosely based on drivers/net/-wireless/ airo_cs.c, the client driver for the Cisco Aironet 4500 and 4800 series of PCMCIA WiFi cards. The listing uses the services of the PCMCIA core to do the following:
6/25/2008
2 p 271 6. The kernel invokes the bus probe() operation registered by Driver Services in Step 5. This in turn, invokes the probe() method owned by the matching client driver (airo_probe()), also registered in Step 5. The client probe() routine populates settings, such as I/O windows and interrupt lines, and configures the generic chipset-specific driver (drivers/net/wireless/airo.c), as shown in Listing 9.2.
6. The kernel invokes the bus probe() operation registered by Driver Services in Step 5, which in turn invokes the probe() method owned by the matching client driver (airo_probe()), registered in Step 5. The client probe() routine populates settings such as I/O windows and interrupt lines, and configures the generic chipset-specific driver (drivers/net/wireless/airo.c), as shown in Listing 9.2.
6/25/2008
2 p 272 • Miniature IDE disk drives or microdrives. These are tiny versions of mechanical hard drives that use magnetic media. Their data transfer rates are typically higher than solid state memory devices, but IDE drives have spin-up and seek latencies before data can be transferred. The IDE Card Services driver ide_cs, in conjunction with legacy IDE drivers, is used to communicate with such memory cards.
• Solid-state memory cards that emulate IDE. Such cards have no moving parts and are usually based on flash memory, which is transparent to the operating system because of the IDE emulation. Because these drives are effectively IDE- based, the same IDE Card Services driver (ide_cs) can be used to talk to them.
• Memory cards that use flash memory, but without IDE emulation. The memory_cs Card Services driver provides block and character interfaces over such cards. The block interface is used to put a filesystem onto card memory, whereas the character interface is used to access raw data. You may also use memory_cs to read the attribute memory space of any PCMCIA card.
Serial PCMCIA
Many networking technologies such as General Packet Radio Service (GPRS), Global System for Mobile Communications (GSM), Global Positioning System (GPS), and Bluetooth use a serial transport mechanism to communicate with host systems. In this
• Miniature IDE disk drives or microdrives. These are tiny versions of mechanical hard drives that use magnetic media. Their data transfer rates are typically higher than solid state memory devices, but IDE drives have spin-up and seek latencies before data can be transferred. The IDE Card Services driver ide_cs, in conjunction with legacy IDE drivers, is used to communicate with such memory cards.
• Solid-state memory cards that emulate IDE. Such cards have no moving parts and are usually based on flash memory, which is transparent to the operating system because of the IDE emulation. Because these drives are effectively IDE- based, the same IDE Card Services driver (ide_cs) can be used to talk to them.
• Memory cards that use flash memory, but without IDE emulation. The memory_cs Card Services driver provides block and character interfaces over such cards. The block interface is used to put a filesystem onto card memory, whereas the character interface is used to access raw data. You may also use memory_cs to read the attribute memory space of any PCMCIA card.
Serial PCMCIA
Many networking technologies such as General Packet Radio Service (GPRS), Global Positioning System (GPS), Global System for Mobile Communications (GSM), and Bluetooth use a serial transport mechanism to communicate with host systems. In this
6/25/2008
2 p 273 The Point-to-Point Protocol (PPP) allows networking protocols such as TCP/IP to run over a serial link. In the context of Figure 9.5, PPP gets TCP/IP applications running over GPRS and GSM dialup. The PPP daemon, pppd, attaches over virtual serial ports emulated by serial_cs. The PPP kernel modules—ppp_generic, ppp_async, and slhc—have to be loaded for pppd to work. Invoke pppd as follows:
The Point-to-Point Protocol (PPP) allows networking protocols such as TCP/IP to run over a serial link. In the context of Figure 9.5, PPP gets TCP/IP applications running over GPRS and GSM dialup. The PPP daemon, pppd, attaches over virtual serial ports emulated by serial_cs. The PPP kernel modules—ppp_generic, ppp_async, and slhc—have to be loaded for pppd to work. Invoke pppd as follows:
6/25/2008
2 p 274 Information about PC Card client drivers is available in the process filesystem entry, /proc/bus/pccard/drivers. Look at /sys/bus/pcmcia/devices/* for card-specific information such as manufacturer and card IDs. Take a look inside /proc/bus/pci/ to know more about your PCMCIA host controller if your system uses a PCI-to-PCMCIA bridge. /proc/interrupts lists IRQs active on your system, including those used by the PCMCIA layer.
Information about PC Card client drivers is available in the process filesystem entry /proc/bus/pccard/drivers. Look at /sys/bus/pcmcia/devices/* for card-specific information such as manufacturer and card IDs. Take a look inside /proc/bus/pci/ to know more about your PCMCIA host controller if your system uses a PCI-to-PCMCIA bridge. /proc/interrupts lists IRQs active on your system, including those used by the PCMCIA layer.
6/25/2008
2 p 278 Mini PCI, also a 33MHz 32-bit bus, is another adaptation of PCI found in small-footprint computers such as laptops. A PCI card can talk via a Mini PCI slot using a compatible connector.
Mini PCI, also a 33MHz 32-bit bus, is another adaptation of PCI found in small-footprint computers such as laptops. A PCI card can connect to a Mini PCI slot using a compatible connector.
6/25/2008
2 p 284 bash> od -x /sys/devices/pci0000:00/0000:00:1e.0/0000:02:00.0/0000:03:00.1/config
bash> od -x /sys/devices/pci0000:00/0000:00:1e.0/0000:02:00.0/0000:03:00.0/config
6/25/2008
2 p 285 pci_read_config_[byte|word|dword](struct pci_dev *pdev,
int offset, int *value);
and
pci_write_config_[byte|word|dword](struct pci_dev *pdev,
int offset, int value);
pci_read_config_[byte|word|dword](struct pci_dev *pdev,
int offset, int *value);
and
pci_write_config_[byte|word|dword](struct pci_dev *pdev,
int offset, int value);
6/25/2008
2 p 286 As per the PCI specification, offset 60 inside the PCI configuration space holds the IRQ number assigned to the card. All configuration register offsets are expressively defined in include/linux/pci_regs.h, so use PCI_INTERRUPT_LINE rather than 60 to specify this offset. Similarly, to read the PCI status register (two bytes at offset six in the configuration space), do this:
unsigned short status;
pci_read_config_word(pdev, PCI_STATUS, &status);
• Only the first 64 bytes of the configuration space are standardized. The device manufacturer defines desired semantics to the rest. The Xircom card used earlier, assigns four bytes at offset 64 for power management purposes. To disable power management, the Xircom CardBus driver, drivers/net/tulip/xircom_cb.c, does this:
#define PCI_POWERMGMT 0x40
pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000);
I/O and Memory
PCI cards have up to six I/O or memory regions. I/O regions contain registers, and memory regions hold data. Video cards, for example, have I/O spaces that accommodate control registers and memory regions that map to frame buffers. Not all cards have addressable memory regions, however. The semantics of I/O and memory spaces are hardware-dependent and can be obtained from the device data sheet.
As per the PCI specification, offset 60 inside the PCI configuration space holds the IRQ number assigned to the card. All configuration register offsets are expressively defined in include/linux/pci_regs.h, so use PCI_INTERRUPT_LINE rather than 60 to specify this offset. Similarly, to read the PCI status register (two bytes at offset six in the configuration space), do this:
unsigned short status;
pci_read_config_word(pdev, PCI_STATUS, &status);
• Only the first 64 bytes of the configuration space are standardized. The device manufacturer defines desired semantics to the rest. The Xircom card used earlier, assigns four bytes at offset 64 for power management purposes. To disable power management, the Xircom CardBus driver drivers/net/tulip/xircom_cb.c, does this:
#define PCI_POWERMGMT 0x40
pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000);
I/O and Memory
PCI cards have up to six I/O or memory regions. I/O regions contain registers, and memory regions hold data. Video cards, for example, may have I/O spaces that accommodate control registers and memory regions that map to frame buffers. Not all cards have addressable memory regions, however. The semantics of I/O and memory spaces are hardware-dependent and can be obtained from the device data sheet.
6/26/2008
2 p 287 This assumes that the device control registers for this card are mapped to the memory region associated with bar, whose value can range from 0 through 5, as shown in Table 10.2.
2. Mark this region as being spoken for, using the kernel’s request_region() regulatory mechanism discussed in Chapter 5, “Character Drivers”:
request_region(io_base, length, "my_driver");
Here, length is the size of the control register space and my_driver identifies the region’s owner. Look for the entry containing my_driver in /proc/ioports to spot this memory region.
You may instead use the wrapper function pci_request_region(), defined in drivers/pci/pci.c.
3. Add the register’s offset obtained from the data-sheet, to the base address gleaned in Step 1. Operate on this address using the inb() and outb() family of functions discussed in Chapter 5:
/* Read */
register_data = inl(io_base + REGISTER_OFFSET);
/* Use */
/* ... */
/* Write */
outl(register_data, iobase + REGISTER_OFFSET);
To operate on a memory region such as the frame buffer on the above PCI video card, follow these steps:
This assumes that the device control registers for this card are mapped to the IO region associated with bar, whose value can range from 0 through 5, as shown in Table 10.2.
2. Mark this region as being spoken for, using the kernel’s request_region() regulatory mechanism discussed in Chapter 5, “Character Drivers”:
request_region(io_base, length, "my_driver");
Here, length is the size of the control register space and my_driver identifies the region’s owner. Look for the entry containing my_driver in /proc/ioports to spot this memory region.
You may use the wrapper function pci_request_region(), defined in drivers/pci/pci.c, instead of calling request_region().
3. Add the register’s offset obtained from the data-sheet, to the base address gleaned in Step 1. Operate on this address using the inb() and outb() family of functions discussed in Chapter 5:
/* Read */
register_data = inl(io_base + REGISTER_OFFSET);
/* Use */
/* ... */
/* Write */
outl(register_data, iobase + REGISTER_OFFSET);
To operate on a memory region such as a frame buffer on the above PCI video card, follow these steps:
6/26/2008
2 p 288 The issue of cache coherency is synonymous with DMA. For optimum performance, processors cache recently accessed bytes, so data passing between the CPU and main memory streams through the processor cache. During DMA, however, data travels directly between the DMA controller and main memory and, hence, bypasses the processor cache. This evasion has the potential to introduce inconsistencies because the The issue of cache coherency is synonymous with DMA. For optimum performance, processors cache recently accessed bytes, so data passing between the CPU and main memory streams through the processor cache. During DMA, however, data travels directly between the peripheral device and main memory and, hence, bypasses the processor cache. This evasion has the potential to introduce inconsistencies because the 6/26/2008
2 p 290 There are a couple more concepts worth knowing about DMA. One is the idea of bounce buffers. Bounce buffers reside in DMA-able regions and are used as temporary memory when DMA is requested to/from non-DMA-able memory regions. An example is DMA to an address higher than 4GB from a 32-bit PCI peripheral when there is no intervening IOMMU. Data is first transferred to a bounce buffer and then copied to the final destination. The second concept is a flavor of DMA called scatter-gather. When data to be DMA’ed is spread over discontinuous regions, scatter-gather capability enables the hardware to gather contents of the scattered buffers at one go. The reverse occurs when data is DMA’ed from the card to buffers scattered in memory. Scatter-gather capability boosts performance by eliminating the need to service multiple DMA requests.
There are a couple more concepts worth knowing about DMA. One is the idea of bounce buffers. Bounce buffers reside in DMA-able regions and are used as temporary memory when DMA is requested to/from non-DMA-able memory regions. An example is DMA to an address higher than 4GB from a 32-bit PCI peripheral when there is no intervening IOMMU. Data is first transferred to a bounce buffer and then copied to the final destination. The second concept is a flavor of DMA called scatter-gather. When data to be DMA’ed is spread over discontiguous regions, scatter-gather capability enables the hardware to gather contents of the scattered buffers at one go. The reverse occurs when data is DMA’ed from the card to buffers scattered in memory. Scatter-gather capability boosts performance by eliminating the need to service multiple DMA requests.
6/26/2008
2 p 292 entries in the scatterlist. The first and last arguments are the same as that described for pci_map_single(). The function returns the number of mapped entries:
entries in scatterlist. The first and last arguments are the same as that described for pci_map_single(). The function returns the number of mapped entries:
6/26/2008
2 p 293 The Ethernet and modem portions of the Xircom driver live separately in drivers/net/tulip/xircom_cb.c and drivers/serial/8250_pci.c, respectively.
The Ethernet and modem portions of the Xircom driver live separately in drivers/net/tulip/xircom_cb.c and drivers/serial/8250_pci.c, respectively.
6/26/2008
2 p 298 /* The net_device structure is defined in include/linux/netdevice.h.
See Chapter 15, "Network Interface Cards", for the description */
struct net_device *net_dev;
/* The net_device structure is defined in include/linux/netdevice.h.
See Chapter 15, "Network Interface Cards," for the description */
struct net_device *net_dev;
6/26/2008
2 p 302 typo in figure:

(dma_buffer_tx/dma_bus_rx)
should be:

(dma_buffer_tx/dma_bus_tx)
6/26/2008
2 p 302 Listing 10.5Setting Up DMA Descriptors and Buffers
/* Device-specific data structure for the Ethernet Function */
struct device_data {
struct pci_dev *pdev; /* The PCI Device structure */
struct net_device *ndev; /* The Net Device structure */
void *dma_buffer_rx; /* Kernel virtual address of the
receive descriptor */
Listing 10.5Setting Up DMA Descriptors and Buffers
/* Device-specific data structure for the Ethernet Function
allocated during device initialization */
struct device_data {
struct pci_dev *pdev; /* The PCI Device structure */
struct net_device *ndev; /* The Net Device structure */
void *dma_buffer_rx; /* Kernel virtual address of the
receive descriptor */
6/26/2008
2 p 305 Listing 10.6Receiving and Transmitting Data
/* The interrupt handler */
static irqreturn_t
mydevice_interrupt(int irq, void *devid)
{
struct sk_buff *skb;
/* ... */
/* If this is a receive interrupt, collect the packet and pass it
on to higher layers. Look at the control word in each RX DMA
descriptor to figure out whether it contains data. Assume for
convenience that the first RX descriptor was used by the card
to DMA this received packet */

packet_size = mydev_data->dma_buffer_rx[1];
Listing 10.6Receiving and Transmitting Data
/* The interrupt handler */
static irqreturn_t
mydevice_interrupt(int irq, void *devid)
{
struct sk_buff *skb;
/* ... */
/* If this is a receive interrupt, collect the packet and pass it
on to higher layers. Look at the control word in each RX DMA
descriptor to figure out whether it contains data. Assume for
convenience that the first RX descriptor was used by the card
to DMA this received packet */
packet_size = mydev_data->dma_buffer_rx[1];
6/26/2008
2 p 307 /* Ring of receive buffers */
struct rx_list {
void *dma_buffer_rx; /* Kernel virtual address of the
transmit descriptor */
dma_addr_t dma_bus_rx; /* Bus address of the transmit
descriptor */
unsigned int size; /* Buffer size */
struct list_head next_desc; /* Pointer to the next element */
struct sk_buff *skb; /* Network Packet */
dma_addr_t sk_bus; /* Bus address of network packet */
} *rxlist;

/* Ring of transmit buffers */
struct tx_list {
void *dma_buffer_tx; /* Kernel virtual address of the
receive descriptor */
dma_addr_t dma_bus_tx; /* Bus address of the transmit
descriptor */
unsigned int size; /* Buffer size */
struct list_head next_desc; /* Pointer to the next element */
struct sk_buff *skb; /* Network Packet */
dma_addr_t sk_bus; /* Bus address of network packet */
} *txlist;
/* Ring of receive buffers */
struct rx_list {
void *dma_buffer_rx; /* Kernel virtual address of the
receive descriptor */
dma_addr_t dma_bus_rx; /* Bus address of the receive
descriptor */
unsigned int size; /* Buffer size */
struct list_head next_desc; /* Pointer to the next element */
struct sk_buff *skb; /* Network Packet */
dma_addr_t sk_bus; /* Bus address of network packet */
} *rxlist;

/* Ring of transmit buffers */
struct tx_list {
void *dma_buffer_tx; /* Kernel virtual address of the
transmit descriptor */
dma_addr_t dma_bus_tx; /* Bus address of the transmit
descriptor */
unsigned int size; /* Buffer size */
struct list_head next_desc; /* Pointer to the next element */
struct sk_buff *skb; /* Network Packet */
dma_addr_t sk_bus; /* Bus address of network packet */
} *txlist;
6/26/2008
2 p 319 Let’s take a peek inside a URB. The following definition is from include/linux/usb.h, omitting fields not of particular interest to device drivers: Let’s take a peek inside a URB. The following definition is from include/linux/usb.h, omitting fields not of particular interest to device drivers:
6/26/2008
2 p 320 The USB core also offers wrapper interfaces that provide a façade of synchronous URB submission:
The USB core also offers wrapper interfaces that provide a facade of synchronous URB submission:
6/26/2008
2 p 321 A URB is associated with an abstraction called a pipe, which we discuss next.
A URB is associated with an abstraction called a pipe, which we discuss next.
6/26/2008
2 p 325 Let’s build a minimal driver for this card partly based on the USB skeleton driver, drivers/usb/usb-skeleton.c.
Let’s build a minimal driver for this card partly based on the USB skeleton driver drivers/usb/usb-skeleton.c.
6/26/2008
2 p 338 The USB specification introduces the concept of device classes and describes the functionality of each class driver. Examples of standard device classes include mass storage, networking, hubs, serial converters, audio, video, imaging, modems, printers, and human interface devices (HIDs). Class drivers are generic and let you plug and play a wide array of cards without the need for developing and installing drivers for every single device. The Linux-USB subsystem includes support for major class drivers.
The USB specification introduces the concept of device classes and describes the functionality of each class driver. Examples of standard device classes include mass storage, networking, hubs, serial converters, audio, video, imaging, modems, printers, and human interface devices. Class drivers are generic and let you plug and play a wide array of cards without the need for developing and installing drivers for every single device. The Linux-USB subsystem includes support for major class drivers.
6/26/2008
2 p 350 with the kernel’s soft USB tracer, usbmon. This tool captures traffic between USB host controllers and devices. To collect a trace, read from the debugfs file /sys/kernel/debug/usbmon/Xt, where X is the bus number to which your device is connected.
For example, consider a USB disk connected to a PC. From the associated “T:” line in /proc/bus/usb/devices, you can see that the drive is attached to bus 1:
with the kernel’s soft USB tracer, usbmon. This tool captures traffic between USB host controllers and devices. To collect a trace, read from the debugfs file /sys/kernel/debug/usbmon/Xt, where X is the bus number to which your device is connected.
For example, consider a USB disk connected to a PC. From the associated “T:” line in /proc/bus/usb/devices, you can see that the drive is attached to bus 1:
6/26/2008
2 p 351 You can glean device and bus specific information from the USB filesystem (usbfs) node, /proc/bus/usb/devices. And as we discuss in Chapter 19, “Drivers in User Space,” usbfs also lets you implement USB device drivers in user space. Even when the final destination of your USB driver is inside the kernel, starting with a user-space driver can ease debugging and testing.
You can glean device and bus specific information from the USB filesystem (usbfs) node /proc/bus/usb/devices. And as we discuss in Chapter 19, “Drivers in User Space,” usbfs also lets you implement USB device drivers in user space. Even when the final destination of your USB driver is inside the kernel, starting with a user-space driver can ease debugging and testing.
6/26/2008
2 p 358 The embedded device, as in Figure 12.3, supports dual display panels: an internal LVDS flat-panel LCD and an external DVI monitor. The internal TFT LCD takes an LVDS connector as input, so an LVDS transmitter chip is used to convert the flat-panel signals to LVDS. Figure 12.3 shows an embedded device that supports dual display panels: an internal LVDS flat-panel LCD and an external DVI monitor. The internal TFT LCD takes an LVDS connector as input, so an LVDS transmitter chip is used to convert the flat-panel signals to LVDS. 6/26/2008
2 p 362 Let’s next wet our feet in the frame buffer API. The frame buffer core layer exports device nodes to user space so that applications can access each supported video device. /dev/fbX is the node associated with frame buffer device X. The following are the main data structures that interest users of the frame buffer API. Inside the kernel, they are defined in include/linux/fb.h, whereas in user land, their definitions reside in /usr/include/linux/fb.h:
Let’s next wet our feet in the frame buffer API. The frame buffer core layer exports device nodes to user space so that applications can access each supported video device. /dev/fbX is the node associated with frame buffer device X. The following are the main data structures that interest users of the frame buffer API. Inside the kernel, they are defined in include/linux/fb.h, whereas in user land, their definitions reside in /usr/include/linux/fb.h:
6/26/2008
2 p 371 Bit lengths used by the RGB encoding (5+6+5=16 in this case) is called the color depth, which is used by the frame buffer console driver to choose the logo file to display during boot (see the section “Boot Logo”).
Screen Blanking
The fb_blank() method provides support for blanking and unblanking the display. This is mainly used for power management. To blank the navigation system’s display after a 10-minute period of inactivity, do this:
bash> setterm -blank 10
This command percolates down the layers to the frame buffer layer and results in the invocation of myfb_blank(), which programs appropriate bits in CTRL_REG.
Bit lengths used by the RGB encoding (5+6+5=16 in this case) is called the color depth, which is used by the frame buffer console driver to choose the logo file to display during boot (see the section “Boot Logo”).
Screen Blanking
The fb_blank() method provides support for blanking and unblanking the display. This is mainly used for power management. To blank the navigation system’s display after a 10-minute period of inactivity, do this:
bash> setterm -blank 10
This command percolates down the layers to the frame buffer driver and results in the invocation of myfb_blank(), which programs appropriate bits in CTRL_REG.
6/26/2008
2 p 383 Figure 12.7 shows the position of our example USB_UART console driver within the Linux-Video subsystem. As you can see, the USB_UART is a simple device that needs only a top-level console driver.
Figure 12.5 shows the position of our example USB_UART console driver within the Linux-Video subsystem. As you can see, the USB_UART is a simple device that needs only a top-level console driver.
6/26/2008
2 p 398 Listing 13.1 is a skeletal ALSA audio driver for the MP3 player and liberally employs pseudo code (within comments) to cut out extraneous detail. ALSA is a sophisticated framework, and conforming audio drivers are usually several thousand lines long. Listing 13.1 gets you started only on your audio driver explorations. Continue your learning by falling back to the mighty Linux-Sound sources inside the top-level sound/ directory.
Listing 13.1 is a skeletal ALSA audio driver for the MP3 player and liberally employs pseudo code (within comments) to cut out extraneous detail. ALSA is a sophisticated framework, and conforming audio drivers are usually several thousand lines long. Listing 13.1 only gets you started on your audio driver explorations. Continue your learning by falling back to the mighty Linux-Sound sources inside the top-level sound/ directory.
6/26/2008
2 p 400 struct snd_pcm {
struct snd_card *card; /* Associated snd_card */
/* ... */
struct snd_pcm_str streams[2]; /* Playback and capture streams of this PCM
component. Each stream may support
substreams if your h/w supports it
*/
/* ... */
struct device *dev; /* Associated hardware
device */
};
The snd_device_new() routine lies at the core of snd_pcm_new() and other similar component instantiation functions. snd_device_new() ties a component and a set of operations with the associated snd_card (see Step 3).
3. Connects playback operations with the PCM instance created in Step 2, by calling snd_pcm_set_ops(). The snd_pcm_ops structure specifies these operations for transferring PCM audio to the codec. Listing 13.1 accomplishes this as follows:
struct snd_pcm {
struct snd_card *card; /* Associated snd_card */
/* ... */
struct snd_pcm_str streams[2]; /* Playback and capture streams of this PCM
component. Each stream may support
substreams if your h/w supports it
*/
/* ... */
struct device *dev; /* Associated hardware
device */
};
3. Connects playback operations with the PCM instance created in Step 2, by calling snd_pcm_set_ops(). The snd_pcm_ops structure specifies these operations for transferring PCM audio to the codec. Listing 13.1 accomplishes this as follows:
6/26/2008
2 p 401 In Listing 13.1, mycard_pb_prepare() configures the sampling rate into the SAMPLING_RATE_REGISTER, clock source into the CLOCKING_INPUT_REGISTER, and transmit complete interrupt enablement into the CONTROL_REGISTER. The trigger() method, mycard_pb_trigger(), maps an audio buffer populated by the ALSA framework on-the-fly using dma_map_single(). (We discussed streaming DMA in Chapter 10, “Peripheral Component Interconnect.”) The mapped DMA buffer address is programmed into the DMA_ADDRESS_REGISTER. This register is part of the audio controller in the SoC, unlike the earlier registers that reside inside the codec. The audio controller forwards the DMA’ed data to the codec for playback.
In Listing 13.1, mycard_pb_prepare() configures the sampling rate into the SAMPLING_RATE_REGISTER, clock source into the CLOCK_INPUT_REGISTER, and transmit complete interrupt enablement into the CONTROL_REGISTER. The trigger() method, mycard_pb_trigger(), maps an audio buffer populated by the ALSA framework on-the-fly using dma_map_single(). (We discussed streaming DMA in Chapter 10, “Peripheral Component Interconnect.”) The mapped DMA buffer address is programmed into the DMA_ADDRESS_REGISTER. This register is part of the audio controller in the SoC, unlike the earlier registers that reside inside the codec. The audio controller forwards the DMA’ed data to the codec for playback.
6/26/2008
2 p 410 Open the mixer node, /dev/snd/controlC0. The third argument to snd_ctl_open() specifies the card number in the node name:
Open the mixer node /dev/snd/controlC0. The third argument to snd_ctl_open() specifies the card number in the node name:
6/26/2008
2 p 412 If you think you have found a bug in an ALSA driver, post it to the alsa-devel mailing list (http://mailman.alsa-project.org/mailman/listinfo/alsa-devel). The linux-audio-dev mailing list (http://music.columbia.edu/mailman/listinfo/linux-audio-dev/), also called the Linux Audio Developers (LAD) list, discusses questions related to the Linux-sound architecture and audio applications.
If you think you have found a bug in an ALSA driver, post it to the alsa-devel mailing list (http://mailman.alsa-project.org/mailman/listinfo/alsa-devel). The linux-audio-dev mailing list (http://mailman.alsa-project.org/mailman/listinfo/alsa-devel), also called the Linux Audio Developers (LAD) list, discusses questions related to the Linux-sound architecture and audio applications.
6/26/2008
2 p 420 PCMCIA/ CF storage cards PCMCIA/CF form factor of miniature IDE drives, or solid-state memory cards that emulate IDE. See the section “PCMCIA Storage” in Chapter 9. drivers/ide/legacy/ide-cs.cordrivers/ata/pata_pcmcia.c (experimental)
PCMCIA/ CF storage cards PCMCIA/CF form factor of miniature IDE drives, or solid-state memory cards that emulate IDE. See the section “PCMCIA Storage” in Chapter 9. drivers/ide/legacy/ide-cs.cordrivers/ata/pata_pcmcia.c (Experimental)
6/26/2008
2 p 428 The block device is now available to the system as /dev/myblkdev. If the device supports multiple disk partitions, they appear as /dev/myblkdevX, where X is the partition number.
The block device is now available to the system as /dev/myblkdev. If the device supports multiple disk partitions, they appear as /dev/myblkdevX, where X is the partition number.
6/26/2008
2 p 433 case READ:
/* Issue Read Sector Command */
outb(READ_SECTOR_CMD, COMMAND_REGISTER);
/* Traverse all requested sectors, byte by byte */
for (i = 0; i < 512*req->nr_sectors; i++) {
/* Wait until the disk is ready. Busy duration should be
in the order of microseconds. Sitting in a tight loop
for simplicity; more intelligence required in the real
world */
while ((status = inb(STATUS_REGISTER)) & BUSY_STATUS);

/* Read data from disk to the buffer associated with the
request */
req->buffer[i] = inb(DATA_REGISTER);
}
good = 1;
break;
case WRITE:
case READ:
/* Issue Read Sector Command */
outb(READ_SECTOR_CMD, COMMAND_REGISTER);
/* Traverse all requested sectors, byte by byte */
for (i = 0; i < 512*req->nr_sectors; i++) {
/* Wait until the disk is ready. Busy duration should be
in the order of microseconds. Sitting in a tight loop
for simplicity; more intelligence required in the real
world */
while ((status = inb(STATUS_REGISTER)) & BUSY_STATUS);

/* Read data from disk to the buffer associated with the
request */
req->buffer[i] = inb(DATA_REGISTER);
}
good = 1;
break;
case WRITE:
6/26/2008
2 p 434 /* Wait until the disk is ready. Busy duration should be
in the order of microseconds. Sitting in a tight loop
for simplicity; more intelligence required in the real
world */
while ((status = inb(STATUS_REGISTER)) & BUSY_STATUS);
/* Wait until the disk is ready. Busy duration should be
in the order of microseconds. Sitting in a tight loop
for simplicity; more intelligence required in the real
world */
while ((status = inb(STATUS_REGISTER)) & BUSY_STATUS);
6/26/2008
2 p 436 Self-Monitoring, Analysis, and Reporting Technology (SMART) is a system built in to many modern ATA and SCSI disks to monitor failures and perform self-tests. A user-space daemon named smartd collects the information gathered by SMART-capable disks with the help of the underlying device driver. Look at the man pages of smartd, smartctl, and smartd.conf to learn how to obtain health status from SMART-enabled disks.
Self-Monitoring, Analysis, and Reporting Technology (SMART) is a system built in to many modern ATA and SCSI disks to monitor failures and perform self-tests. A user-space daemon named smartd collects the information gathered by SMART-capable disks with the help of the underlying device driver. Look at the man pages of smartd, smartctl, and smartd.conf to learn how to obtain health status from SMART-enabled disks.
6/26/2008
2 p 441 Assume skb points to an sk_buff, skb->head, skb->data, skb->tail, and skb->end slide over the associated packet buffer as the packet traverses the protocol stack in either direction. skb->data, for example, points to the header of the protocol that is currently processing the packet. When a packet reaches the IP layer via the receive path, skb->data points to the IP header; when the packet passes on to TCP, however, skb->data moves to the start of the TCP header. And as the packet drives through various protocols adding or discarding header data, skb->len gets updated, too. sk_buffs also contain pointers other than the four major ones previously mentioned. skb->nh, for example, remembers the position of the network protocol header irrespective of the current position of skb->data.
Assuming that skb points to an sk_buff, skb->head, skb->data, skb->tail, and skb->end slide over the associated packet buffer as the packet traverses the protocol stack in either direction. skb->data, for example, points to the header of the protocol that is currently processing the packet. When a packet reaches the IP layer via the receive path, skb->data points to the IP header; when the packet passes on to TCP, however, skb->data moves to the start of the TCP header. And as the packet drives through various protocols adding or discarding header data, skb->len gets updated, too. sk_buffs also contain pointers other than the four major ones previously mentioned. skb->nh, for example, remembers the position of the network protocol header irrespective of the current position of skb->data.
6/26/2008
2 p 444 The net_device interface requires conventional methods such as open(), close(), and ioctl(). The kernel opens an interface when you activate it using a tool such as ifconfig:
The net_device interface requires conventional methods such as open(), close(), and ioctl(). The kernel opens an interface when you activate it using a tool such as ifconfig:
6/26/2008
2 p 445 netdev->tx_timeout = &mycard_timeout; /* Method to reset the NIC */
netdev->watchdog_timeo = 8*HZ; /* Reset if no response
detected for 8 seconds */
netdev->tx_timeout = &mycard_timeout; /* Method to reset the NIC */
netdev->watchdog_timeo = 8*HZ; /* Reset if no activity
detected for 8 seconds */
6/26/2008
2 p 453 if (receive_interrupt) {
/* We were interrupted due to packet reception. At this point,
the NIC has already DMA'ed received data to an sk_buff that
was pre-allocated and mapped during device open. Obtain the
address of the sk_buff depending on your data structure
design and assign it to 'skb'. 'length' is similarly obtained
from the NIC by reading the descriptor used to DMA data from
the card. Now, skb->data contains the receive data. */
/* ... */
if (receive_interrupt) {
/* We were interrupted due to packet reception. At this point,
the NIC has already DMA'ed received data to an sk_buff that
was pre-allocated and mapped during device open. Obtain the
address of the sk_buff depending on your data structure
design and assign it to 'skb'. 'length' is similarly obtained
from the NIC by reading the descriptor used to DMA data from
the card. Now, skb->data contains the received data. */
/* ... */
6/26/2008
2 p 454 /* Fill transmit and receive rings */
/* See the section,
"Buffer Management and Concurrency Control" */
/* ... */
/* Allocate Descriptor rings */
/* See the section,
"Buffer Management and Concurrency Control" */
/* ... */
6/26/2008
2 p 459 Several tools are available to benchmark network performance. Netperf, available for free from www.netperf.org, can set up complex TCP/UDP connection scenarios. You can use scripts to control characteristics such as protocol parameters, number of simultaneous sessions, and size of data blocks. Benchmarking is accomplished by comparing the resulting throughput with the maximum practical bandwidth that the networking technology yields. For example, a 155Mbps ATM adapter produces a maximum IP throughput of 135Mbps, taking into account the ATM cell header size, overheads due to the ATM Adaptation Layer (AAL), and the occasional maintenance cells sent by the physical Synchronous Optical Networking (SONET) layer.
Several tools are available to benchmark network performance. Netperf, available for free from www.netperf.org, can set up complex TCP/UDP connection scenarios. You can use scripts to control characteristics such as protocol parameters, number of simultaneous sessions, and size of data blocks. Benchmarking is accomplished by comparing the resulting throughput with the maximum practical bandwidth that the networking technology yields. For example, a 155Mbps ATM adapter produces a maximum IP throughput of 135Mbps, taking into account the ATM cell header size, overheads due to the ATM Adaptation Layer (AAL), and the occasional maintenance cells sent by the physical Synchronous Optical Networking (SONET) layer.
6/26/2008
2 p 466 Several small-footprint devices are powered by the dual combination of a wireless technology and Linux. Bluetooth, Infrared, WiFi, and cellular networking are established wireless technologies that have healthy Linux support. Bluetooth eliminates cables, injects intelligence into dumb devices, and opens a flood gate of novel applications. Infrared is a low-cost, low-range, medium-rate, wireless technology that can network laptops, connect handhelds, or dispatch a document to a printer. WiFi is the wireless equivalent of an Ethernet LAN. Cellular networking using General Packet Radio Service (GPRS) or code division multiple access (CDMA) keeps you Internet-enabled on the go, as long as your wanderings are confined to service provider coverage area.
Several small-footprint devices are powered by the dual combination of a wireless technology and Linux. Bluetooth, Infrared, WiFi, and cellular networking are established wireless technologies that have healthy Linux support. Bluetooth eliminates cables, injects intelligence into dumb devices, and opens a flood gate of novel applications. Infrared is a low-cost, low-range, medium-rate, wireless technology that can network laptops, connect handhelds, or dispatch a document to a printer. WiFi is the wireless equivalent of an Ethernet LAN. Cellular networking using GPRS or code division multiple access (CDMA) keeps you Internet-enabled on the go, as long as your wanderings are confined to service provider coverage area.
6/26/2008
2 p 468 In figure 16.1:

Link Layer
changed to:

Link Controller
6/26/2008
2 p 469 6. The Human Interface Devices (HID) layer is implemented via hidp.ko. The user mode daemon, hidd, lets BlueZ handle input devices such as Bluetooth mice.
6. The HID layer is implemented via hidp.ko. The user mode daemon hidd lets BlueZ handle input devices such as Bluetooth mice.
6/26/2008
2 p 471 The read data path for the Sharp Bluetooth card is shown in Figure 16.3. The first point of contact between the card and the kernel is at the UART driver. As you saw in Figure 9.5 of Chapter 9, “PCMCIA and Compact Flash,” the serial Card Services driver, drivers/serial/serial_cs.c, allows the rest of the operating system to see the Sharp card as if it were a serial device. The serial driver passes on the received HCI packets to BlueZ. BlueZ implements HCI processing in the form of a kernel line discipline. As you learned in Chapter 6, “Serial Drivers,” line disciplines reside above the serial driver and shape its behavior. The HCI line discipline invokes associated protocol routines (H4 in this case) for assistance in data processing. From then on, L2CAP and higher BlueZ layers take charge.
The read data path for the Sharp Bluetooth card is shown in Figure 16.3. The first point of contact between the card and the kernel is at the UART driver. As you saw in Figure 9.5 of Chapter 9, “PCMCIA and Compact Flash,” the serial Card Services driver drivers/serial/serial_cs.c, allows the rest of the operating system to see the Sharp card as if it were a serial device. The serial driver passes on the received HCI packets to BlueZ. BlueZ implements HCI processing in the form of a kernel line discipline. As you learned in Chapter 6, “Serial Drivers,” line disciplines reside above the serial driver and shape its behavior. The HCI line discipline invokes associated protocol routines (H4 in this case) for assistance in data processing. From then on, L2CAP and higher BlueZ layers take charge.
6/26/2008
2 p 473 You also saw in Chapter 11 that when a USB device is plugged into a system, the host controller driver enumerates it using a control pipe and assigns endpoint addresses between 1 and 127. The configuration descriptor read by the USB subsystem during enumeration contains information about the device, such as its class, subclass, and protocol. The Bluetooth specification defines the (class, subclass, -protocol) codes of Bluetooth USB devices as (0xE, 0x01, 0x01). The HCI USB transport driver (hci_usb) registers these values with the USB core during initialization. When the Belkin USB adapter is plugged in, the USB core reads the (class, subclass, protocol) information from the device configuration descriptor. Because this information matches the values registered by hci_usb, this driver gets attached to the Belkin USB adapter. hci_usb reads Bluetooth data from the four USB pipes described previously and passes it on to the BlueZ protocol stack. Linux applications now run seamlessly over this device, as shown in Figure 16.2.
You also saw in Chapter 11 that when a USB device is plugged into a system, the host controller driver enumerates it using a control pipe and assigns endpoint addresses between 1 and 127. The configuration descriptor read by the USB subsystem during enumeration contains information about the device, such as its class, subclass, and protocol. The Bluetooth specification defines the (class, subclass, -protocol) codes of Bluetooth USB devices as (0xE, 0x01, 0x01). The HCI USB transport driver (hci_usb) registers these values with the USB core during initialization. When the Belkin USB adapter is plugged in, the USB core reads the (class, subclass, protocol) information from the device configuration descriptor. Because this information matches the values registered by hci_usb, this driver gets attached to the Belkin USB adapter. hci_usb reads Bluetooth data from the four USB pipes described previously and passes it on to the BlueZ protocol stack. Linux applications now run seamlessly over this device, as shown in Figure 16.2.
6/26/2008
2 p 477 Bluetooth chipsets commonly have PCM interface pins in addition to the HCI transport interface. If a device supports, for instance, both Bluetooth and Global System for Mobile Communication (GSM), the PCM lines from the GSM chipset may be directly wired to the Bluetooth chip’s PCM audio lines. You might then have to configure the Bluetooth chip to receive and send SCO audio packets over its HCI interface instead of its PCM interface.
Bluetooth chipsets commonly have PCM interface pins in addition to the HCI transport interface. If a device supports, for instance, both Bluetooth and GSM, the PCM lines from the GSM chipset may be directly wired to the Bluetooth chip’s PCM audio lines. You might then have to configure the Bluetooth chip to receive and send SCO audio packets over its HCI interface instead of its PCM interface.
6/26/2008
2 p 487 • Insert irlan.ko. This creates the network interface, irlanX, where X is the assigned interface number.
• Insert irlan.ko. This creates the network interface irlanX, where X is the assigned interface number.
6/26/2008
2 p 489 Look inside drivers/net/irda/ for IrDA low-level drivers, net/irda/ for the protocol implementation, and include/net/irda/ for the header files. Experiment with proc/sys/net/irda/* to tune the IrDA stack and explore /proc/net/irda/* for state information pertaining to different IrDA layers.
Look inside drivers/net/irda/ for low-level IrDA drivers, net/irda/ for the protocol implementation, and include/net/irda/ for the header files. Experiment with /proc/sys/net/irda/* to tune the IrDA stack and explore /proc/net/irda/* for state information pertaining to different IrDA layers.
6/26/2008
2 p 490 The Wireless Extensions project defines a generic Linux API to configure WLAN device drivers in a device-independent manner. It also provides a set of common tools to set and access information from WLAN drivers. Individual drivers implement support for Wireless Extensions to connect themselves with the common interface and, hence, with the tools.
The Wireless Extensions project defines a generic Linux API to configure WLAN device drivers in a device-independent manner. It also provides a collection of common tools to set and access information from WLAN drivers. Individual drivers implement support for Wireless Extensions to connect themselves with the common interface, and hence, with the tools.
6/26/2008
2 p 497 The above driver descriptions also hold for driving Global Positioning System (GPS) receivers and networking over GSM. The above driver descriptions also hold for driving GPS receivers and networking over GSM.
6/26/2008
2 p 500 At one end of today’s on-the-move connectivity spectrum, there are standards that allow coupling between cellular networks and WiFi to provide cheaper networking solutions. At the other end, technologies such as Bluetooth and Infrared are being integrated into GPRS cell phones to bridge consumer electronics devices with the Internet. Figure 16.7 shows a sample scenario.
At one end of today’s on-the-move connectivity spectrum, there are standards that allow coupling between cellular networks and WiFi to provide cheaper networking solutions. At the other end, technologies such as Bluetooth and Infrared are being integrated into cell phones to bridge consumer electronics devices with the Internet. Figure 16.7 shows a sample scenario.
6/26/2008
2 p 504 Flash memory chips generally come in two flavors: NOR and NAND. NOR is the variety used to store firmware images on embedded devices, whereas NAND is used for large, dense, cheap, but imperfect storage as required by solid-state mass storage media such as USB pen drives and Disk-On-Modules (DOMs). NOR flash chips are connected to the processor via address and data lines like normal RAM, but NAND flash chips are interfaced using I/O and control lines. So, code resident on NOR flash can be executed in place, but that stored on NAND flash has to be copied to RAM before execution.
Flash memory chips generally come in two flavors: NOR and NAND. NOR is the variety used to store firmware images on embedded devices, whereas NAND is used for large, dense, cheap, but imperfect storage as required by solid-state mass storage media such as USB pen drives and Disk-On-Modules (DOMs). NOR flash chips are connected to the processor via address and data lines like normal RAM, but NAND flash chips are interfaced using I/O and control lines. So, code resident on NOR flash can be executed in place, but that stored on NAND flash has to be copied to RAM before execution.
6/26/2008
2 p 505 Adjust bottom right arrow so that it ends just above the dotted line. done 6/26/2008
2 p 513 Because of this unconventional mode of addressing, you need special drivers to work with NAND storage. MTD provides such drivers to manage NAND-resident data. If you are using a supported chip, you have to enable only the appropriate low-level MTD NAND driver. If you are writing a NAND flash driver, however, you need to explore two datasheets: the NAND flash controller and the NAND flash chip.
Because of this unconventional mode of addressing, you need special drivers to work with NAND storage. MTD provides such drivers to manage NAND-resident data. If you are using a supported chip, you have to only enable the appropriate low-level MTD NAND driver. If you are writing a NAND flash driver, however, you need to explore two datasheets: that of the NAND flash controller and the NAND flash chip.
6/26/2008
2 p 515 figure adjustments:

move second line over 2 spaces to right.

NAND Chip line - change 38 to 40
done 6/26/2008
2 p 516 The MTD subsystem provides a block driver called mtdblock that emulates a hard disk over flash memory. You can put any filesystem, say EXT2, over the emulated flash disk. Mtdblock hides complicated flash access procedures (such as preceding a write with an erase of the corresponding sector) from the filesystem. Device nodes created by mtdblock are named /dev/mtdblock/X, where X is the partition number. To create an EXT2 filesystem on the pda_fs partition of the handheld, as shown in Figure 17.2, do the following:
bash> mkfs.ext2 /dev/mtdblock/2 Æ Create an EXT2 filesystem
on the second partition
bash> mount /dev/mtdblock/2 /mnt Æ Mount the partition
As you will soon see, it’s a much better idea to use JFFS2 rather than EXT2 to hold files on flash filesystem partitions.
The MTD subsystem provides a block driver called mtdblock that emulates a hard disk over flash memory. You can put any filesystem, say EXT2, over the emulated flash disk. Mtdblock hides complicated flash access procedures (such as preceding a write with an erase of the corresponding sector) from the filesystem. Device nodes created by mtdblock are named /dev/mtdblock/X, where X is the partition number. To create an EXT2 filesystem on the pda_fs partition of the handheld, shown in Figure 17.2, do the following:
bash> mkfs.ext2 /dev/mtdblock/2 Æ Create an EXT2 filesystem
on the second partition
bash> mount /dev/mtdblock/2 /mnt Æ Mount the partition
As you will soon see, it’s a much better idea to use JFFS2 rather than EXT2 to hold files on flash partitions.
6/26/2008
2 p 517 The mtdchar driver presents a linear view of the underlying flash device, rather than the block-oriented view required by filesystems. Device nodes created by mtdchar are named /dev/mtd/X, where X is the partition number. You may update the bootloader partition of the handheld as shown in Figure 17.2, by using dd over the corresponding mtdchar interface:
The mtdchar driver presents a linear view of the underlying flash device, rather than the block-oriented view required by filesystems. Device nodes created by mtdchar are named /dev/mtd/X, where X is the partition number. You may update the bootloader partition of the handheld shown in Figure 17.2, by using dd over the corresponding mtdchar interface:
6/26/2008
2 p 524 The Linux-MTD project page www.linux-mtd.infradead.org has FAQs, various pieces of documentation, and a Linux-MTD JFFS HOWTO that provides insights into JFFS2 design. The linux-mtd mailing list is the place to discuss questions related to MTD device drivers. Look at http://lists.infradead.org/pipermail/linux-mtd/ for the mailing list archives.
Looking at the Sources
In the kernel tree, the drivers/mtd/ directory contains the sources for the MTD layer. Map, chip, and NAND drivers live in the drivers/mtd/maps/, drivers/mtd/chips/, and
The Linux-MTD project page www.linux-mtd.infradead.org has FAQs, various pieces of documentation, and a Linux-MTD JFFS HOWTO that provides insights into JFFS2 design. The linux-mtd mailing list is the place to discuss questions related to MTD device drivers. Look at /http://lists.infradead.org/pipermail/linux-mtd/ for the mailing list archives.
Looking at the Sources
In the kernel tree, the drivers/mtd/ directory contains the sources for the MTD subsystem. Map, chip, and NAND drivers live in the drivers/mtd/maps/, drivers/mtd/chips/, and drivers/mtd/nand/ subdirectories, respectively. Most MTD data structures are defined in header files present in include/linux/mtd/.
6/26/2008
2 p 531 2. Glibc, the set of C libraries that you will need when you build applications for the target device.
3. Binutils, which includes the cross-assembler, and tools such as objdump.
2. Glibc, the set of C libraries that you will need when you build applications for the target device.
3. Binutils, which includes the cross-assembler, and tools such as objdump.
6/26/2008
2 p 536 In figure 18.2:

Align Phase 2 under Phase 1
done 6/26/2008
2 p 543 If your embedded device contains circuitry to detect brownout, you might need to add capability to the kernel to sense that condition and take appropriate action.
If your embedded device contains circuitry to detect brownout, you might need to add capability to the kernel to sense that condition and take appropriate action.
6/26/2008
2 p 546 Configure the DHCP server. The kernel on the embedded device relies on this server to assign it the 4.1.1.2 IP address during boot and to supply /path/to/target/root/:
Configure the DHCP server. The kernel on the embedded device relies on this server to assign it the 4.1.1.2 IP address during boot and to supply /path/to/target/root/:
6/26/2008
2 p 549 A multimeter and an oscilloscope are worthy additions to your embedded debugging toolkit. As an illustration, let’s consider an example situation involving the I2C RTC, as shown in Figure 8.3 of Chapter 8. A multimeter and an oscilloscope are worthy additions to your embedded debugging toolkit. As an illustration, let’s consider an example situation involving the I2C RTC as shown in Figure 8.3 of Chapter 8. 6/26/2008
2 p 552 Most device drivers prefer to lead a privileged life inside the kernel, but some are at home in the indeterministic world outside. Several kernel subsystems, such as SCSI, USB, and I2C, offer some level of support for user mode drivers, so you might be able to control those devices without writing a single line of kernel code.
Most device drivers prefer to lead a privileged life inside the kernel, but some are at home in the indeterministic world outside. Several kernel subsystems such as SCSI, USB, and I2C, offer some level of support for user mode drivers, so you might be able to control those devices without writing a single line of kernel code.
6/27/2008
2 p 560 In Chapter 5, you learned to talk to your computer’s parallel port via a kernel driver. Let’s now implement a sample program that interacts with a parallel port device from user space. The kernel’s parallel port subsystem provides a character driver called ppdev that exports parallel port access to user land. Ppdev creates device nodes, /dev/parportX, where X is the parallel port number. Applications can open /dev/parportX, exchange data via read()/write() system calls, and issue a variety of ioctl() commands. Using kernel interfaces, such as ppdev, is preferable to directly operating over I/O ports using ioperm(), iopl(), or /dev/port. The former technique is safer, works across architectures, and functions over different device form factors such as USB-to-parallel converters.
In Chapter 5, you learned to talk to your computer’s parallel port via a kernel driver. Let’s now implement a sample program that interacts with a parallel port device from user space. The kernel’s parallel port subsystem provides a character driver called ppdev that exports parallel port access to user land. Ppdev creates device nodes /dev/parportX, where X is the parallel port number. Applications can open /dev/parportX, exchange data via read()/write() system calls, and issue a variety of ioctl() commands. Using kernel interfaces such as ppdev, is preferable to directly operating over I/O ports using ioperm(), iopl(), or /dev/port. The former technique is safer, works across architectures, and functions over different device form factors such as USB-to-parallel converters.
6/27/2008
2 p 562 1. Graphical user interfaces, such as X Windows (www.xfree86.org) and SVGAlib (www.svgalib.org), mmap video memory and directly access graphics hardware.
2. Madplay is an integer-only MP3 player that runs on several architectures. Memory mapping improves throughput, so madplay mmaps MP3 files for faster access. This helps maintain the correct bit rates necessary for high-quality music playback.
3. MPEG (Moving Picture Experts Group) decoders play movies by directly operating on mmapped frame buffer memory.
The prototype of the mmap() system call looks like this:
void *mmap(void *start, size_t length, int prot, int flag,
int fd, off_t offset);
This requests the kernel to associate the device file specified by the file descriptor fd to a chunk of user memory beginning at start. (start is only a preference and is usually set to 0; the actual associated memory is returned by mmap().) The kernel maps length bytes of memory starting from offset in the specified file. prot specifies the desired access protection, and flag describes the type of the mapping. The MAP_SHARED flag mirrors your modifications to other users of the same memory region, whereas MAP_PRIVATE keeps your changes to yourself.
All mmapped pages need not be present in physical memory. Areas not being accessed can be in swap space from where they are paged in on demand. Underlying device drivers may control the semantics of the mmap() system call by implementing an mmap() method.
Listing 19.4 is an image display program that illustrates usage of mmap() as follows:
• Mmaps a frame buffer. (We discussed frame buffer drivers in Chapter 12, “Video Drivers.”)
• Mmaps an image file.
1. Graphical user interfaces such as X Windows (www.xfree86.org) and SVGAlib (www.svgalib.org), mmap video memory and directly access graphics hardware.
2. Madplay is an integer-only MP3 player that runs on several architectures. Memory mapping improves throughput, so madplay mmaps MP3 files for faster access. This helps maintain the correct bit rates necessary for high-quality music playback.
3. MPEG (Moving Picture Experts Group) decoders play movies by directly operating on mmapped frame buffer memory.
The prototype of the mmap() system call looks like this:
void *mmap(void *start, size_t length, int prot, int flag,
int fd, off_t offset);
This requests the kernel to associate the device file specified by the file descriptor fd to a chunk of user memory beginning at start. (start is only a preference and is usually set to 0; the actual associated memory is returned by mmap().) The kernel maps length bytes of memory starting from offset in the specified file. prot specifies the desired access protection, and flag describes the type of the mapping. The MAP_SHARED flag mirrors your modifications to other users of the same memory region, whereas MAP_PRIVATE keeps your changes to yourself.
All mmapped pages need not be present in physical memory. Areas not being accessed can be in swap space from where they are paged in on demand. Underlying device drivers may control the semantics of the mmap() system call by implementing an mmap() method.
Listing 19.4 is an image display program that performs the following to illustrate usage of mmap():
• Mmaps an image file.
• Mmaps a frame buffer. (We discussed frame buffer drivers in Chapter 12, “Video Drivers.”)
6/27/2008
2 p 563 • Transfers the latter to the former after performing necessary transformations depending on the properties of the image file (not shown in the listing).
• Transfers the former to the latter after performing necessary transformations depending on the properties of the image file (not shown in the listing).
6/27/2008
2 p 565 Let’s learn how to use the sg interface with the help of an example. Listing 19.5 implements a user program that sends a READ_CAPACITY SCSI command to a storage device, such as a SCSI hard disk or a USB mass storage drive to glean its data capacity. The READ_CAPACITY command consists of 10 bytes, starting with the command code 0x25. For the purpose of this example, let’s set the rest of the bytes to zero. When a SCSI device receives a READ_CAPACITY command, it responds with an 8-byte reply; the top 4 bytes contain the address of the last logical block, and the bottom 4 bytes contain the block length.
sg device nodes are named /dev/sgX, where X is the device number, so Listing 19.5 opens /dev/sg0, which is assumed to be the sg char node corresponding to your SCSI storage device. It then sets about populating the sg_io_hdr_t structure, which is the main data structure that sg users have to manage. The read(), write(), and ioctl()calls expect a pointer to this structure (defined in /usr/include/scsi/sg.h) as an argument. The cmdp field of sg_io_hdr_t is set to the address of the command block that holds the 10-byte READ_CAPACITY command. The dxferp field supplies the address of a buffer that will carry the response data arriving from the device. The sbp field contains the address of a sense buffer that will return the status of the requested operation. The interface_id has to be set to S, and timeout holds the wait time in milliseconds before sg gives up on the command.
Let’s learn how to use the sg interface with the help of an example. Listing 19.5 implements a user program that sends a READ_CAPACITY SCSI command to a storage device such as a SCSI hard disk or a USB mass storage drive to glean its data capacity. The READ_CAPACITY command consists of 10 bytes, starting with the command code 0x25. For the purpose of this example, let’s set the rest of the bytes to zero. When a SCSI device receives a READ_CAPACITY command, it responds with an 8-byte reply; the top 4 bytes contain the address of the last logical block, and the bottom 4 bytes contain the block length.
sg device nodes are named /dev/sgX, where X is the device number, so Listing 19.5 opens /dev/sg0, which is assumed to be the sg char node corresponding to your SCSI storage device. It then sets about populating the sg_io_hdr_t structure, which is the main data structure that sg users have to manage. The read(), write(), and ioctl()calls expect a pointer to this structure (defined in /usr/include/scsi/sg.h) as an argument. The cmdp field of sg_io_hdr_t is set to the address of the command block that holds the 10-byte READ_CAPACITY command. The dxferp field supplies the address of a buffer that will carry the response data arriving from the device. The sbp field contains the address of a sense buffer that will return the status of the requested operation. The interface_id has to be set to S, and timeout holds the wait time in milliseconds before sg gives up on the command.
6/27/2008

p 572 /* Connect to the first bank */
if (ioctl(smbus_fp, I2C_SLAVE, EEPROM_SLAVE_ADDR1) < 0) {
exit(1);
}

/* ... */
/* Connect to the first bank */
if (ioctl(smbus_fp, I2C_SLAVE, SLAVE_ADDR1) < 0) {
exit(1);
}

/* ... */
6/27/2008
2 p 574 iopl() Controls access privileges to all I/O ports
iopl() Changes the I/O privilege level of the calling process
6/27/2008
2 p 578 EDAC reports errors via files in the sysfs directory, /sys/devices/system/edac/. It also generates messages that can be gleaned from the kernel error log.
EDAC reports errors via files in the sysfs directory /sys/devices/system/edac/. It also generates messages that can be gleaned from the kernel error log.
6/27/2008
2 p 583 • Userspace lets applications dictate the scaling technique. Some distributions set the governor to userspace and implement the scaling algorithm via a daemon called cpuspeed, which is spawned during boot.
• Userspace lets applications dictate the scaling technique. Some distributions set the governor to userspace and implement the scaling algorithm via a daemon called cpuspeed, which is spawned during boot.
6/27/2008
2 p 584 If you now monitor the running frequency by looking at /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq, you will see it dancing to the tune of the CPU load.
If you now monitor the running frequency by looking at /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq, you will see it dancing to the tune of the CPU load.
6/27/2008
2 p 585 As you saw elsewhere in this book, low-level code is not the place to implement policy. This was the main problem with APM, where most of the power-management policies were part of BIOS firmware. ACPI shifts policy one level up, to the operating system. Using a daemon called acpid, ACPI even allows policy to be pushed one more level up, to user-space configuration files. By adding rules to an acpid configuration file, you can decide what to do when a hotkey is pressed or when a thermal trip occurs.
As you saw elsewhere in this book, low-level code is not the place to implement policy. This was the main problem with APM, where most of the power-management policies were part of BIOS firmware. ACPI shifts policy one level up, to the operating system. Using a daemon called acpid, ACPI even allows policy to be pushed one more level up, to user-space configuration files. By adding rules to an acpid configuration file, you can decide what to do when a hotkey is pressed or when a thermal trip occurs.
6/27/2008
2 p 588 Look at drivers/net/tokenring/skisa.c for a sample ISA driver for a Token Ring card. The IBM Token Ring driver, drivers/net/tokenring/ibmtr.c, supports ISA, PnP, and MCA form factors of IBM Token Ring hardware. The 3COM Ethernet driver, drivers/net/3c509.c, drives MCA, PnP, and EISA form factors of a 3COM Ethernet card. The kernel provides core routines for the use of PnP, EISA, and MCA drivers. These implementations live in drivers/pnp/, drivers/eisa/, and drivers/mca/, respectively.
Look at drivers/net/tokenring/skisa.c for a sample ISA driver for a Token Ring card. The IBM Token Ring driver, drivers/net/tokenring/ibmtr.c, supports ISA, PnP, and MCA form factors of IBM Token Ring hardware. The 3COM Ethernet driver, drivers/net/3c509.c, drives MCA, PnP, and EISA form factors of a 3COM Ethernet card. The kernel provides core routines for the use of PnP, EISA, and MCA drivers. These implementations live in drivers/pnp/, drivers/eisa/, and drivers/mca/, respectively.
6/27/2008
2 p 592 Fibre Channel is a modern high-speed serial bus protocol used to talk with storage systems. Fibre Channel interface cards have fiber-optic ports to talk to storage devices on SANs. Fibre Channel is compatible with SCSI, so a Fibre Channel device driver is essentially a SCSI driver with extras to handle fiber channels.
Fibre Channel is a modern high-speed serial bus protocol used to talk with storage systems. Fibre Channel interface cards have fiber-optic ports to talk to storage devices on SANs. Fibre Channel is compatible with SCSI, so an associated device driver is essentially a SCSI driver with extras to handle fiber channels.
6/27/2008
2 p 593 iSCSI is another SAN technology. It allows the transport of SCSI packets over TCP/IP networks. With iSCSI, a remote block device appears to your system as local storage. The remote system owning the storage is called an iSCSI target, and local systems using the storage are called iSCSI initiators.
iSCSI is another SAN technology. It allows the transport of SCSI packets over TCP/IP networks. With iSCSI, a remote block device appears to your system as local storage. The remote system owning the storage is called an iSCSI target, and local systems using the storage are called iSCSI initiators.
6/27/2008
2 p 599 kdb> id rs_open Æ Disassemble rs_open
0xc01cce00 rs_open: sub $0x1c, %esp
0xc01cce03 rs_open+0x03: mov $ffffffed, %ecx
...
0xc01cce4b rs_open+0x4b: call 0xc01ccca0, get_async_struct
...
0xc01cce56 rs_open+0x56: mov 0xc(%esp,1), %eax
0xc01cce5a rs_open+0x5a: mov %eax, 0x9a4(%ebx)
...
Point A in the source code is a good place to attach a breakpoint because you can peek at both the tty structure and the info structure to see what’s going on.
Looking side by side at the source and the disassembly, rs_open+0x5a corresponds to Point A. Note that correlation is easier if the kernel is compiled without optimization flags.
Set a breakpoint at rs_open+0x5a (which is address 0xc01cce5a) and continue execution by exiting the debugger:
kbd> bp rs_open+0x5a Æ Set breakpoint
kbd> go Æ Continue execution
kdb> id rs_open Æ Disassemble rs_open
0xc01cce00 rs_open: sub $0x1c, %esp
0xc01cce03 rs_open+0x03: mov $ffffffed, %ecx
...
0xc01cce4b rs_open+0x4b: call 0xc01ccca0, get_async_struct
...
0xc01cce56 rs_open+0x56: mov 0xc(%esp,1), %eax
0xc01cce5a rs_open+0x5a: mov %eax, 0x9a4(%ebx)
...
Point A in the source code is a good place to attach a breakpoint because you can peek at both the tty structure and the info structure to see what’s going on.
Looking side by side at the source and the disassembly, rs_open+0x5a corresponds to Point A. Note that correlation is easier if the kernel is compiled without optimization flags.
Set a breakpoint at rs_open+0x5a (which is address 0xc01cce5a) and continue execution by exiting the debugger:
kbd> bp rs_open+0x5a Æ Set breakpoint
kbd> go Æ Continue execution
6/27/2008
2 p 600 kbd> r Æ Dump register contents
eax = 0xcf1ae680 ebx = 0xce03b000 ecx = 0x00000000
...
So, 0xcf1ae680 is the address of the info structure. Dump its contents using the md command:
kbd> md 0xcf1ae680 Æ Memory dump
0xcf1ae680 00005301 0000ABC 00000000 10000400
kbd> r Æ Dump register contents
eax = 0xcf1ae680 ebx = 0xce03b000 ecx = 0x00000000
...
So, 0xcf1ae680 is the address of the info structure. Dump its contents using the md command:
kbd> md 0xcf1ae680 Æ Memory dump
0xcf1ae680 00005301 0000ABC 00000000 10000400
6/27/2008
2 p 601 If your host computer is a laptop that does not have a serial port, you may use a USB-to-serial converter for the debug session. In that case, instead of /dev/ttySX, use the /dev/ttyUSBX node created by the usbserial driver. Figure 6.4 of Chapter 6, “Serial Drivers,” illustrates this scenario.
If your host computer is a laptop that does not have a serial port, you may use a USB-to-serial converter for the debug session. In that case, instead of /dev/ttySX, use the /dev/ttyUSBX node created by the usbserial driver. Figure 6.4 of Chapter 6, “Serial Drivers,” illustrates this scenario.
6/27/2008
2 p 603 bash> gdb vmlinux Æ vmlinux is the uncompressed kernel

(gdb) target remote /dev/ttySX Æ Connect to the target
bash> gdb vmlinux Æ vmlinux is the uncompressed kernel

(gdb) target remote /dev/ttySX Æ Connect to the target
6/27/2008
2 p 605 bash> gdb vmlinux /proc/kcore

(gdb) p xtime Æ Test the waters by printing a kernel variable
$0 = 1113173755
Repeated access to the same variable will not yield refreshed values due to gdb’s cached access. You can force a fresh access by rereading the core file using gdb’s core-file command. Let’s now look at the disassembly of trojan_function():
(gdb) x/2i trojan_function Æ Disassemble trojan_function
0xc019d710 <trojan_function>: mov 0xab, %eax
0xc019d715 <trojan_function+5>: ret
bash> gdb vmlinux /proc/kcore

(gdb) p xtime Æ Test the waters by printing a kernel variable
$0 = 1113173755
Repeated access to the same variable will not yield refreshed values due to gdb’s cached access. You can force a fresh access by rereading the core file using gdb’s core-file command. Let’s now look at the disassembly of trojan_function():
(gdb) x/2i trojan_function Æ Disassemble trojan_function
0xc019d710 <trojan_function>: mov 0xab, %eax
0xc019d715 <trojan_function+5>: ret
6/27/2008
2 p 608 figure 21.2 correction:

insert line connecting Remote Power Switch box and Target Hardware box.
done 6/27/2008
2 p 617 When Listing 21.4 invokes register_jprobes() to register the jprobe, a kprobe is inserted at the beginning of printk(). When this probe is hit, Kprobes replace the saved return address with that of the registered jprobe handler, jprintk(). It then copies a portion of the stack and returns, thus passing control to jprintk() with printk()’s argument list. When jprintk() calls jprobe_return(), the original call state is restored, and printk() continues to execute normally.
When Listing 21.4 invokes register_jprobes() to register the jprobe, a kprobe is inserted at the beginning of printk(). When this probe is hit, Kprobes replaces the saved return address with that of the registered jprobe handler, jprintk(). It then copies a portion of the stack and returns, thus passing control to jprintk() with printk()’s argument list. When jprintk() calls jprobe_return(), the original call state is restored, and printk() continues to execute normally.
6/27/2008
2 p 619 When tty_open() returns via any of its seven return paths, control returns to the trampoline instead of the caller function. The trampoline invokes the kretprobe handler, kret_tty_open() registered by Listing 21.5, which prints the return value if tty_open() has not returned successfully.
When tty_open() returns via any of its seven return paths, control returns to the trampoline instead of the caller function. The trampoline invokes the kretprobe handler kret_tty_open(), registered by Listing 21.5, which prints the return value if tty_open() has not returned successfully.
6/27/2008
2 p 621 2. Boot into the second kernel:
bash> kexec -e
... Æ Kernel boot up messages
Kexec abruptly starts the new kernel without gracefully halting the operating system. To shut down prior to reboot, invoke kexec from the bottom of the halt script (usually /etc/rc.d/rc0.d/S01halt) and invoke halt instead.
2. Boot into the second kernel:
bash> kexec -e
... Æ Kernel boot up messages
Kexec abruptly starts the new kernel without gracefully halting the operating system. To shut down prior to reboot, invoke kexec from the bottom of the halt script (usually /etc/rc.d/rc0.d/S01halt) and invoke halt instead.
6/27/2008
2 p 624 bash> hwclock
... Æ Kernel panic occurs when execution hits rtc_interrupt()
causing kexec to boot into the capture kernel.
bash> hwclock
... Æ Kernel panic occurs when execution hits rtc_interrupt()
causing kexec to boot into the capture kernel.
6/27/2008
2 p 626 Alt-Sysrq-c
... Æ Messages announcing that a crash dump
has been triggered
Alt-Sysrq-c
... Æ Messages announcing that a crash dump
has been triggered
6/27/2008
2 p 630 bash> opcontrol -l Æ List available events on a Pentium 4 CPU
GLOBAL_POWER_EVENTS: (counter: 0, 4)
time during which processor is not stopped (min count: 3000)
BRANCH_RETIRED: (counter: 3, 7)
retired branches (min count: 3000)
MISPRED_BRANCH_RETIRED: (counter: 3, 7)
retired mispredicted branches (min count: 3000)
BSQ_CACHE_REFERENCE: (counter: 0, 4)
...
Next, start OProfile and run a benchmarking tool that stresses those parts of the kernel you would like to profile. Look at http://lbs.sourceforge.net/ for a list of benchmarking projects on Linux. For this example, let’s exercise the Virtual File System (VFS) layer by recursively listing all files in the system:
bash> opcontrol --start Æ Start data collection
bash> ls -lR / Æ Stress test
bash> opcontrol --dump Æ Save profiled data
bash> opcontrol -l Æ List available events on a Pentium 4 CPU
GLOBAL_POWER_EVENTS: (counter: 0, 4)
time during which processor is not stopped (min count: 3000)
BRANCH_RETIRED: (counter: 3, 7)
retired branches (min count: 3000)
MISPRED_BRANCH_RETIRED: (counter: 3, 7)
retired mispredicted branches (min count: 3000)
BSQ_CACHE_REFERENCE: (counter: 0, 4)
...
Next, start OProfile and run a benchmarking tool that stresses those parts of the kernel you would like to profile. Look at http://lbs.sourceforge.net/ for a list of benchmarking projects on Linux. For this example, let’s exercise the Virtual File System (VFS) layer by recursively listing all files in the system:
bash> opcontrol --start Æ Start data collection
bash> ls -lR / Æ Stress test
bash> opcontrol --dump Æ Save profiled data
6/27/2008
2 p 631 bash> opreport -l /path/to/kernelsources/vmlinux

CPU: P4 / Xeon, speed 2992.9 MHz (estimated)
Counted GLOBAL_POWER_EVENTS events (time during which processor
is not stopped) with a unit mask of 0x01 (count cycles when processor is active)
count 100000
samples % symbol name
914506 24.2423 vgacon_scroll Æ ls output printed to console
406619 10.7789 do_con_write
273023 7.2375 vgacon_cursor
206611 5.4770 __d_lookup
...
1380 0.0366 vfs_readdir Æ Our routine of interest
...
1 2.7e-05 vma_prio_tree_next
bash> opreport -l /path/to/kernelsources/vmlinux

CPU: P4 / Xeon, speed 2992.9 MHz (estimated)
Counted GLOBAL_POWER_EVENTS events (time during which processor
is not stopped) with a unit mask of 0x01 (count cycles when processor is active)
count 100000
samples % symbol name
914506 24.2423 vgacon_scroll Æ ls output printed to console
406619 10.7789 do_con_write
273023 7.2375 vgacon_cursor
206611 5.4770 __d_lookup
...
1380 0.0366 vfs_readdir Æ Our routine of interest
...
1 2.7e-05 vma_prio_tree_next
6/27/2008
2 p 644 void
nfs_unlock_request(struct nfs_page *req)
{
if (!NFS_WBACK_BUSY(req)) {
printk(KERN_ERR "NFS: Invalid unlock attempted\n");
BUG();
}
/* ... */
}
BUG() is defined in include/asm-your-arch/bug.h:
#define BUG() do {\
__asm__ __volatile__ ("ud2\n"\
...
: : "I" (__LINE__), "I"(__FILE__))
void
nfs_unlock_request(struct nfs_page *req)
{
if (!NFS_WBACK_BUSY(req)) {
printk(KERN_ERR "NFS: Invalid unlock attempted\n");
BUG();
}
/* ... */
}
BUG() is defined in include/asm-your-arch/bug.h:
#define BUG() do {\
__asm__ __volatile__ ("ud2\n"\
...
: : "I" (__LINE__), "I"(__FILE__))
6/27/2008
2 p 650 3. Search for a starting point driver inside the mighty kernel source tree. Research candidate drivers and hone in on a suitable one. Certain subsystems offer skeletal drivers that you can model after, if you don’t find a close match. Examples are sound/drivers/dummy.c, drivers/usb/usb-skeleton.c, drivers/net/pci-skeleton.c, and drivers/video/skeletonfb.c.
3. Search for a starting point driver inside the mighty kernel source tree. Research candidate drivers and hone in on a suitable one. Certain subsystems offer skeletal drivers that you can model after, if you don’t find a close match. Examples are sound/drivers/dummy.c, drivers/usb/usb-skeleton.c, drivers/net/pci-skeleton.c, and drivers/video/skeletonfb.c.
6/27/2008
2 p 505 Adjust bottom right arrow so that it ends just above the dotted line. done 10/6/2008
3 p xxx Sreekrishnan Venkateswaran has a master’s degree in computer science from the Indian Institute of Technology, Kanpur, India. During the past 12 years that he has been working for IBM, he has ported Linux to devices such as wristwatches, PDAs, and music players to VoIP phones, pacemaker programmers, and remote patient monitoring systems. Sreekrishnan was a contributing editor and kernel columnist to the Linux Magazine for more than 2 years. Currently, he manages the embedded solutions group at IBM India. Sreekrishnan Venkateswaran has a master’s degree in computer science from the Indian Institute of Technology, Kanpur, India. During the past 12 years that he has been working for IBM, he has ported Linux to devices ranging from wristwatches, PDAs, and music players to VoIP phones, pacemaker programmers, and remote patient monitoring systems. Sreekrishnan was a contributing editor and kernel columnist to the Linux Magazine for more than 2 years. Currently, he manages the embedded solutions group at IBM India. 12/1/2008
3 p 18 x86-based processors have two modes of operation, real mode and protected mode. In real mode, you can access only the first 1MB of memory, that too without any protection. Protected mode is sophisticated and lets you tap into many advanced features of the processor such as paging. The CPU has to pass through real mode en route to protected mode. This road is a one-way street, however. You can’t switch back to real mode from protected mode.
x86-based processors have two modes of operation, real mode and protected mode. In real mode, you can access only the first 1MB of memory, that too without any protection. Protected mode is sophisticated and lets you tap into many advanced features of the processor such as paging. The CPU has to pass through real mode en route to protected mode.
12/1/2008
3 p 20 Make 9th line in figure 2.2 bold done 12/1/2008
3 p 28 Init, the parent of all Linux processes, is the first program to run after the kernel finishes its boot sequence. In the last few lines of init/main.c, the kernel searches different locations in its attempt to locate init: Init, the parent of all Linux processes, is the first program to run after the kernel finishes its boot sequence. In the last few lines of init/main.c, the kernel searches different locations in its attempt to locate init: 12/1/2008
3 p 97 /* Get the waveforms from bits 0, 1 and 2
of Port D as shown in Figure 4.3 */
PA_t =PA_delta_t = PORTD & 0x07;
/* Get the waveforms from bits 0, 1 and 2
of Port D as shown in Figure 4.3 */
PA_t = PA_delta_t = PORTD & 0x07;
12/1/2008
3 p 123 Listing 5.1CMOS Driver Initialization
#include <linux/fs.h>
#include <linux/cdev.h>

/* Per-device (per-bank) structure */
struct cmos_dev {
unsigned short current_pointer; /* Current pointer within the
bank */
unsigned int size; /* Size of the bank */
int bank_number; /* CMOS bank number */
struct cdev cdev; /* The cdev structure */
char name[10]; /* Name of I/O region */
/* ... */ /* Mutexes, spinlocks, wait
queues, .. */
} *cmos_devp;

/* File operations structure. Defined in linux/fs.h */
static struct file_operations cmos_fops = {
.owner = THIS_MODULE, /* Owner */
.open = cmos_open, /* Open method */
.release = cmos_release, /* Release method */
.read = cmos_read, /* Read method */
.write = cmos_write, /* Write method */
.llseek = cmos_llseek, /* Seek method */
.ioctl = cmos_ioctl, /* Ioctl method */
};

static dev_t cmos_dev_number; /* Allotted device number */
struct class *cmos_class; /* Tie with the device model */

#define NUM_CMOS_BANKS 2
#define CMOS_BANK_SIZE (0xFF*8)
#define DEVICE_NAME "cmos"

Listing 5.1CMOS Driver Initialization
#include <linux/fs.h>
#include <linux/cdev.h>

#define NUM_CMOS_BANKS 2

/* Per-device (per-bank) structure */
struct cmos_dev {
unsigned short current_pointer; /* Current pointer within the
bank */
unsigned int size; /* Size of the bank */
int bank_number; /* CMOS bank number */
struct cdev cdev; /* The cdev structure */
char name[10]; /* Name of I/O region */
/* ... */ /* Mutexes, spinlocks, wait
queues, .. */
} *cmos_devp[NUM_CMOS_BANKS];

/* File operations structure. Defined in linux/fs.h */
static struct file_operations cmos_fops = {
.owner = THIS_MODULE, /* Owner */
.open = cmos_open, /* Open method */
.release = cmos_release, /* Release method */
.read = cmos_read, /* Read method */
.write = cmos_write, /* Write method */
.llseek = cmos_llseek, /* Seek method */
.ioctl = cmos_ioctl, /* Ioctl method */
};

static dev_t cmos_dev_number; /* Allotted device number */
struct class *cmos_class; /* Tie with the device model */

#define CMOS_BANK_SIZE (0xFF*8)
#define DEVICE_NAME "cmos"

12/1/2008
3 p 124 /*
* Driver Initialization
*/
int __init
cmos_init(void)
{
int i;

/* Request dynamic allocation of a device major number */
if (alloc_chrdev_region(&cmos_dev_number, 0,
NUM_CMOS_BANKS, DEVICE_NAME) < 0) {
printk(KERN_DEBUG "Can't register device\n"); return -1;
}

/* Populate sysfs entries */
cmos_class = class_create(THIS_MODULE, DEVICE_NAME);

for (i=0; i<NUM_CMOS_BANKS; i++) {
/* Allocate memory for the per-device structure */
cmos_devp = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
if (!cmos_devp) {
printk("Bad Kmalloc\n"); return -ENOMEM;
}

/* Request I/O region */
sprintf(cmos_devp->name, "cmos%d", i);
if (!(request_region(addrports[i], 2, cmos_devp->name)) {
printk("cmos: I/O port 0x%x is not free.\n", addrports[i]);
return –EIO;
}

/*
* Driver Initialization
*/
int __init
cmos_init(void)
{
int i, ret;

/* Request dynamic allocation of a device major number */
if (alloc_chrdev_region(&cmos_dev_number, 0,
NUM_CMOS_BANKS, DEVICE_NAME) < 0) {
printk(KERN_DEBUG "Can't register device\n"); return -1;
}

/* Populate sysfs entries */
cmos_class = class_create(THIS_MODULE, DEVICE_NAME);

for (i=0; i<NUM_CMOS_BANKS; i++) {
/* Allocate memory for the per-device structure */
cmos_devp[i] = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
if (!cmos_devp[i]) {
printk("Bad Kmalloc\n"); return -ENOMEM;
}

/* Request I/O region */
sprintf(cmos_devp[i]->name, "cmos%d", i);
if (!(request_region(addrports[i], 2, cmos_devp[i]->name)) {
printk("cmos: I/O port 0x%x is not free.\n", addrports[i]);
return –EIO;
}

12/1/2008
3 p 125 /* Fill in the bank number to correlate this device
with the corresponding CMOS bank */
cmos_devp->bank_number = i;

/* Connect the file operations with the cdev */
cdev_init(&cmos_devp->cdev, &cmos_fops);
cmos_devp->cdev.owner = THIS_MODULE;

/* Connect the major/minor number to the cdev */
if (cdev_add(&cmos_devp->cdev, (cmos_dev_number + i), 1)) {
printk("Bad cdev\n");
return 1;
}

/* Send uevents to udev, so it'll create /dev nodes */
class_device_create(cmos_class, NULL, (cmos_dev_number + i),
NULL, "cmos%d", i);
}

printk("CMOS Driver Initialized.\n");
return 0;
}


/* Driver Exit */
void __exit
cmos_cleanup(void)
{
int i;

/* Remove the cdev */
cdev_del(&cmos_devp->cdev);

/* Release the major number */
unregister_chrdev_region(cmos_dev_number), NUM_CMOS_BANKS);

/* Release I/O region */
for (i=0; i<NUM_CMOS_BANKS; i++) {
class_device_destroy(cmos_class, (cmos_dev_number) + i))
release_region(addrports[i], 2);
}

/* Fill in the bank number to correlate this device
with the corresponding CMOS bank */
cmos_devp[i]->bank_number = i;

/* Connect the file operations with the cdev */
cdev_init(&cmos_devp[i]->cdev, &cmos_fops);
cmos_devp[i]->cdev.owner = THIS_MODULE;

/* Connect the major/minor number to the cdev */
ret = cdev_add(&cmos_devp[i]->cdev, (cmos_dev_number + i), 1);
if (ret) {
printk("Bad cdev\n");
return ret;
}

/* Send uevents to udev, so it'll create /dev nodes */
device_create(cmos_class, NULL, MKDEV(MAJOR(cmos_dev_number), i),
"cmos%d", i);
}

printk("CMOS Driver Initialized.\n");
return 0;
}


/* Driver Exit */
void __exit
cmos_cleanup(void)
{
int i;

/* Release the major number */
unregister_chrdev_region(cmos_dev_number), NUM_CMOS_BANKS);

/* Release I/O region */
for (i=0; i<NUM_CMOS_BANKS; i++) {
device_destroy (cmos_class, MKDEV(MAJOR(cmos_dev_number), i));
release_region(addrports[i], 2);
cdev_del(&cmos_devp[i]->cdev);
kfree(cmos_devp[i]);
}
12/1/2008
3 p 127 class_create() populates a sysfs entry for this device, and class_device_create() results in the generation of two uevents: cmos0 and cmos1. As you learned in Chapter 4, udevd listens to uevents and generates device nodes after consulting its rules database. Add the following to the udev rules directory (/etc/udev/rules.d/) to produce device nodes corresponding to the two CMOS banks (/dev/cmos/0 and /dev/cmos/1) on receiving the respective uevents (cmos0 and cmos1):
KERNEL="cmos[0-1]*", NAME="cmos/%n"
Device drivers that need to operate on a range of I/O addresses stake claim to the addresses via a call to request_region(). This regulatory mechanism ensures that requests by others for the same region fail until the occupant releases it via a call to release_region(). request_region() is commonly invoked by I/O bus drivers such as PCI and ISA to mark ownership of on-card memory in the processor’s address space (more on this in Chapter 10, “Peripheral Component Interconnect”). cmos_init() requests access to the I/O region of each CMOS bank by calling request_region(). The last argument to request_region() is an identifier used by /proc/ioports, so you will see this if you peek at that file:
class_create() populates a sysfs entry for this device, and device_create() results in the generation of two uevents: cmos0 and cmos1. As you learned in Chapter 4, udevd listens to uevents and generates device nodes after consulting its rules database. Add the following to the udev rules directory (/etc/udev/rules.d/) to produce device nodes corresponding to the two CMOS banks (/dev/cmos/0 and /dev/cmos/1) on receiving the respective uevents (cmos0 and cmos1):
KERNEL="cmos[0-1]*", NAME="cmos/%n"
Device drivers that need to operate on a range of I/O addresses stake claim to the addresses via a call to request_region(). This regulatory mechanism ensures that requests by others for the same region fail until the occupant releases it via a call to release_region(). request_region() is commonly invoked by I/O bus drivers such as PCI and ISA to mark ownership of on-card memory in the processor’s address space (more on this in Chapter 10, “Peripheral Component Interconnect”). cmos_init() requests access to the I/O region of each CMOS bank by calling request_region(). The last argument to request_region() is an identifier used by /proc/ioports, so you will see this if you peek at that file1:


1Before loading the cmos driver, make sure that you’ve unloaded kernel modules such as rtc.ko that might already have staked claim to the I/O address range in question.
12/1/2008
3 p 154 struct class_device *c_d;
If (alloc_chrdev_region (&dev_number, 0, 1, DEVICE_NAME
< 0) {
printk(KERN_DEBUG “Can’t register new device\n”);
return -1

/* Create the pardevice class - /sys/class/pardevice */
led_class = class_create(THIS_MODULE, "pardevice");
if (IS_ERR(led_class)) printk("Bad class create\n");

/* Create the led class device - /sys/class/pardevice/led/ */
c_d = class_device_create(led_class, NULL, dev_number,
NULL, DEVICE_NAME);

/* Register this driver with parport */
if (parport_register_driver(&led_driver)) {
printk(KERN_ERR "Bad Parport Register\n");
return -EIO;
struct class_device *c_d;
if (alloc_chrdev_region (&dev_number, 0, 1, DEVICE_NAME)
< 0) {
printk(KERN_DEBUG "Can’t register new device\n");
return -1;
}
/* Create the pardevice class - /sys/class/pardevice */
led_class = class_create(THIS_MODULE, "pardevice");
if (IS_ERR(led_class)) printk("Bad class create\n");

/* Create the led class device - /sys/class/pardevice/led/ */
c_d = class_device_create(led_class, NULL, dev_number,
NULL, DEVICE_NAME);

/* Register this driver with parport */
if (parport_register_driver(&led_driver)) {
printk(KERN_ERR "Bad Parport Register\n");
return -EIO;
12/2/2008
3 p 160 • Allocates major/minor numbers via alloc_chrdev_region() and friends
• Creates /dev and /sys nodes using class_device_create()
• Registers itself as a char driver using cdev_init() and cdev_add()
• Allocates major/minor numbers via alloc_chrdev_region() and friends
• Creates /dev and /sys nodes using device_create()
• Registers itself as a char driver using cdev_init() and cdev_add()
12/2/2008
3 p 167 • Input drivers are responsible for devices such as keyboards, mice, and joysticks. They live in a separate source directory, drivers/input/, and hence get a distinct chapter, Chapter 7.
• Frame buffers (/dev/fb/*) offer access to video memory, the way /dev/mem exports access to system memory. Chapter 12, “Video Drivers,” looks at frame buffer drivers.
• Some device classes support a minority of hardware possessing a char interface. For example, SCSI devices are generally block devices, but a SCSI tape is a char device.
• Some subsystems export additional char interfaces that present a raw device model to user space. The MTD subsystem is generally used for emulating a disk on top of diverse types of flash memory, but some applications might be better served if they are provided with a raw view of the underlying flash memory. This is done by the MTD char driver, drivers/mtd/mtdchar.c, which is discussed in Chapter 17, “Memory Technology Devices.”
• Input drivers are responsible for devices such as keyboards, mice, and joysticks. They live in a separate source directory drivers/input/, and hence get a distinct chapter, Chapter 7.
• Frame buffers (/dev/fb/*) offer access to video memory, the way /dev/mem exports access to system memory. Chapter 12, “Video Drivers,” looks at frame buffer drivers.
• Some device classes support a minority of hardware possessing a char interface. For example, SCSI devices are generally block devices, but a SCSI tape is a char device.
• Some subsystems export additional char interfaces that present a raw device model to user space. The MTD subsystem is generally used for emulating a disk on top of diverse types of flash memory, but some applications might be better served if they are provided with a raw view of the underlying flash memory. This is done by the MTD char driver drivers/mtd/mtdchar.c, which is discussed in Chapter 17, “Memory Technology Devices.”
12/2/2008
3 p 208 Figure 7.1 illustrates the operation of the input subsystem. The subsystem contains two classes of drivers that work in tandem: event drivers and device drivers. Event drivers are responsible for interfacing with applications, whereas device drivers are responsible for low-level communication with input devices. The mouse event generator, mousedev, is an example of the former, and the PS/2 mouse driver is an example of the latter. Both event drivers and device drivers can avail the services of an efficient, bug-free, reusable core, which lies at the heart of the input subsystem.
Figure 7.1 illustrates the operation of the input subsystem. The subsystem contains two classes of drivers that work in tandem: event drivers and device drivers. Event drivers are responsible for interfacing with applications, whereas device drivers are responsible for low-level communication with input devices. The mouse event generator mousedev, is an example of the former, and the PS/2 mouse driver is an example of the latter. Both event drivers and device drivers can avail the services of an efficient, bug-free, reusable core, which lies at the heart of the input subsystem.
12/2/2008
3 p 212 struct input_dev *vms_input_dev; /* Representation of an input device */
static struct platform_device *vms_dev; /* Device structure */

/* Sysfs method to input simulated
coordinates to the virtual
mouse driver */
static ssize_t
write_vms(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
struct input_dev *vms_input_dev; /* Representation of an input device */
static struct platform_device *vms_dev; /* Device structure */

/* Sysfs method to input simulated
coordinates to the virtual
mouse driver */
static ssize_t
write_vms(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
12/2/2008
3 p 213 /* Register a platform device */
vms_dev = platform_device_register_simple("vms", -1, NULL, 0);
If (IS_ERR(vms_dev)){
printk (“vms_init: error\n”);
return PTR_ERR(vms_dev);
}
}
/* Create a sysfs node to read simulated coordinates */
sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);

/* Allocate an input device data structure */
vms_input_dev = input_allocate_device();
if (!vms_input_dev) {
printk("Bad input_allocate_device()\n"); return -ENOMEM
}

/* Announce that the virtual mouse will generate
relative coordinates */
set_bit(EV_REL, vms_input_dev->evbit);
set_bit(REL_X, vms_input_dev->relbit);
/* Register a platform device */
vms_dev = platform_device_register_simple("vms", -1, NULL, 0);
if (IS_ERR(vms_dev)){
printk ("vms_init: error\n");
return PTR_ERR(vms_dev);
}

/* Create a sysfs node to read simulated coordinates */
sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);

/* Allocate an input device data structure */
vms_input_dev = input_allocate_device();
if (!vms_input_dev) {
printk("Bad input_allocate_device()\n"); return -ENOMEM;
}

/* Announce that the virtual mouse will generate
relative coordinates */
set_bit(EV_REL, vms_input_dev->evbit);
set_bit(REL_X, vms_input_dev->relbit);
12/2/2008
3 p 222 + {
+ /* Allocate input device structure */
+ roller_mouse->dev = input_allocate_device();
+
+ /* Can generate a click and a relative movement */
+ roller_mouse->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);

+ /* Can move only in the Y-axis */
+ roller_mouse->dev->relbit[0] = BIT(REL_Y);
+
+ /* My click should be construed as the left button
+ press of a mouse */
+ roller_mouse->dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT);

+ roller_mouse->dev->name = "roll";
+
+ /* For entries in /sys/class/input/inputX/id/ */
+ oller_mouse->dev->id.bustype = ROLLER_BUS;
+ roller_mouse->dev->id.vendor = ROLLER_VENDOR;
+ roller_mouse->dev->id.product = ROLLER_PROD;
+ roller_mouse->dev->id.version = ROLLER_VER;

+ /* Register with the input subsystem */
+ input_register_device(roller_mouse->dev);
+ }
+ {
+ /* Allocate input device structure */
+ roller_mouse->dev = input_allocate_device();
+
+ /* Can generate a click and a relative movement */
+ roller_mouse->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);

+ /* Can move only in the Y-axis */
+ roller_mouse->dev->relbit[0] = BIT(REL_Y);
+
+ /* My click should be construed as the left button
+ press of a mouse */
+ roller_mouse->dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT);

+ roller_mouse->dev->name = "roll";
+
+ /* For entries in /sys/class/input/inputX/id/ */
+ roller_mouse->dev->id.bustype = ROLLER_BUS;
+ roller_mouse->dev->id.vendor = ROLLER_VENDOR;
+ roller_mouse->dev->id.product = ROLLER_PROD;
+ roller_mouse->dev->id.version = ROLLER_VER;

+ /* Register with the input subsystem */
+ input_register_device(roller_mouse->dev);
+ }
12/2/2008
3 p 224 • The PS/2 mouse driver, drivers/input/mouse/psmouse-base.c, instantiates a psmouse_protocol structure with information regarding supported mouse protocols (including the Synaptics touchpad protocol).
• The PS/2 mouse driver drivers/input/mouse/psmouse-base.c, instantiates a psmouse_protocol structure with information regarding supported mouse protocols (including the Synaptics touchpad protocol).
12/2/2008
3 p 240 }
class_device_create(eep_class, NULL, (dev_number + i),
NULL, "eeprom%d", i);
}
}
device_create(eep_class, NULL, MKDEV(MAJOR(dev_number, i),
"eeprom%d", i);
}
12/2/2008
3 p 251 Most chips that offer hardware monitoring interface to the CPU via I2C/SMBus. Device drivers for such devices are normal I2C client drivers but reside in the drivers/hwmon/ directory, rather than drivers/i2c/chips/. An example is National Semiconductor’s LM87 chip, which can monitor multiple voltages, temperatures, and fans. Have a look at drivers/hwmon/lm87.c for its driver implementation. I2C driver IDs from 1000 to 1999 are reserved for sensor chips (look at include/linux/i2c-id.h).
Most chips that offer hardware monitoring, interface to the CPU via I2C/SMBus. Device drivers for such devices are normal I2C client drivers but reside in the drivers/hwmon/ directory, rather than drivers/i2c/chips/. An example is National Semiconductor’s LM87 chip, which can monitor multiple voltages, temperatures, and fans. Have a look at drivers/hwmon/lm87.c for its driver implementation. I2C driver IDs from 1000 to 1999 are reserved for sensor chips (look at include/linux/i2c-id.h).
12/2/2008
3 p 268 It then configures the chipset-specific driver (XX) with the information previously obtained.
It then configures the chipset-specific driver (XX) with the information thus obtained.
12/2/2008
3 p 271 6. The kernel invokes the bus probe() operation registered by Driver Services in Step 5, which in turn invokes the probe()method owned by the matching client driver (airo_probe()), registered in Step 5. The client probe() routine populates settings such as I/O windows and interrupt lines, and configures the generic chipset-specific driver (drivers/net/wireless/airo.c), as shown in Listing9.2.
6. The kernel invokes the bus probe() operation registered by Driver Services, which in turn invokes the probe()method owned by the matching client driver (airo_probe()), registered in Step 5. The client probe() routine populates settings such as I/O windows and interrupt lines, and configures the generic chipset-specific driver (drivers/net/wireless/airo.c), as shown in Listing9.2.
12/2/2008
3 p 273 The generic serial Card Services driver, serial_cs, allows the rest of the operating system to see the PCMCIA/CF card as a serial device. The first unused serial device, /dev/ttySX, gets allotted to the card. serial_cs thus emulates a serial port over GPRS, GSM, and GPS cards. It also allows Bluetooth PCMCIA/CF cards that use a serial transport to transfer Host Control Interface (HCI) packets to Bluetooth protocol layers.
Figure 9.5 illustrates how kernel modules implementing different networking technologies interact with serial_cs to communicate with their respective cards.
The Point-to-Point Protocol (PPP) allows networking protocols such as TCP/IP to run over a serial link. In the context of Figure 9.5, PPP gets TCP/IP applications running over GPRS and GSM dialup. The PPP daemon, pppd, attaches over virtual serial ports emulated by serial_cs. The PPP kernel modules—ppp_generic, ppp_async, and slhc—have to be loaded for pppd to work. Invoke pppd as follows:
The generic serial Card Services driver serial_cs, allows the rest of the operating system to see the PCMCIA/CF card as a serial device. The first unused serial device /dev/ttySX, gets allotted to the card. serial_cs thus emulates a serial port over GPRS, GSM, and GPS cards. It also allows Bluetooth PCMCIA/CF cards that use a serial transport to transfer Host Control Interface (HCI) packets to Bluetooth protocol layers.
Figure 9.5 illustrates how kernel modules implementing different networking technologies interact with serial_cs to communicate with their respective cards.
The Point-to-Point Protocol (PPP) allows networking protocols such as TCP/IP to run over a serial link. In the context of Figure 9.5, PPP gets TCP/IP applications running over GPRS and GSM dialup. The PPP daemon pppd, attaches over virtual serial ports emulated by serial_cs. The PPP kernel modules—ppp_generic, ppp_async, and slhc—have to be loaded for pppd to work. Invoke pppd as follows:
12/2/2008
3 p 286 • Only the first 64 bytes of the configuration space are standardized. The device manufacturer defines desired semantics to the rest. The Xircom card used earlier, assigns four bytes at offset 64 for power management purposes. To disable power management, the Xircom CardBus driver drivers/net/tulip/xircom_cb.c, does this:
• Only the first 64 bytes of the configuration space are standardized. The device manufacturer defines desired semantics to the rest. The Xircom card used earlier, assigns four bytes at offset 64 for power management purposes. To disable power management, the Xircom CardBus driver drivers/net/tulip/xircom_cb.c, does this:
12/2/2008
3 p 287 Here, length is the size of the control register space and my_driver identifies the region’s owner. Look for the entry containing my_driver in /proc/ioports to spot this memory region.
Here, length is the size of the control register space and my_driver identifies the region’s owner. Look for the entry containing my_driver in /proc/ioports to spot this I/O region.
12/2/2008
3 p 291 The third argument, dma_handle, is a pointer to the bus address that the function call generates. The following snippet allocates and frees a consistent DMA buffer:
The third argument dma_handle, is a pointer to the bus address that the function call generates. The following snippet allocates and frees a consistent DMA buffer:
12/2/2008
3 p 291 The scattered list is specified using the second argument, struct scatterlist, defined in include/asm-your-arch/scatterlist.h. num_entries is the number The scattered list is specified using the second argument struct scatterlist, defined in include/asm-your-arch/scatterlist.h. num_entries is the number 12/2/2008
3 p 297 1. A pointer to pci_dev, the data structure that describes this PCI device. This structure, defined in include/linux/pci.h, is maintained by the PCI subsystem for each PCI device on your system.
1. A pointer to pci_dev, the data structure that describes this PCI device. This structure, defined in include/linux/pci.h, is maintained by the PCI subsystem for each PCI device on your system.
12/2/2008
3 p 302 Listing 10.5Setting Up DMA Descriptors and Buffers
/* Device-specific data structure for the Ethernet Function
allocated during device initialization */
struct device_data {
Listing 10.5Setting Up DMA Descriptors and Buffers
/* Device-specific data structure for the Ethernet Function
allocated during device initialization */
struct device_data {
12/2/2008
3 p 327 Listing 11.3 implements the probe() and disconnect() methods of the telemetry driver. It starts by defining a device-specific structure, tele_device_t, which contains the following fields:
Listing 11.3 implements the probe() and disconnect() methods of the telemetry driver. It starts by defining a device-specific structure tele_device_t, which contains the following fields:
12/2/2008
3 p 328 Khubd invokes the card’s probe() method, tele_probe(), soon after enumeration. tele_probe() performs three tasks:
1. Allocates memory for the device-specific structure, tele_device_t.
Khubd invokes the card’s probe() method tele_probe(), soon after enumeration. tele_probe() performs three tasks:
1. Allocates memory for the device-specific structure tele_device_t.
12/2/2008
3 p 330 /* The probe() method is invoked by khubd after device
enumeration. The first argument, interface, contains information
gleaned during the enumeration process. id is the entry in the
driver’s usb_device_id table that matches the values read from
the telemetry card. tele_probe() is based on skel_probe()
defined in drivers/usb/usb-skeleton.c */
/* The probe() method is invoked by khubd after device
enumeration. The first argument interface, contains information
gleaned during the enumeration process. id is the entry in the
driver’s usb_device_id table that matches the values read from
the telemetry card. tele_probe() is based on skel_probe()
defined in drivers/usb/usb-skeleton.c */
12/2/2008
3 p 349 • A skeletal gadget driver, drivers/usb/gadget/zero.c, that you may use to test device controller drivers.
• A skeletal gadget driver drivers/usb/gadget/zero.c, that you may use to test device controller drivers.
12/2/2008
3 p 350 with the kernel’s soft USB tracer, usbmon. This tool captures traffic between USB host controllers and devices. To collect a trace, read from the debugfs file /sys/kernel/debug/usbmon/Xt, where X is the bus number to which your device is connected.
with the kernel’s soft USB tracer usbmon. This tool captures traffic between USB host controllers and devices. To collect a trace, read from the debugfs file /sys/kernel/debug/usbmon/Xt, where X is the bus number to which your device is connected.
12/2/2008
3 p 356 Figure 12.1 shows the display assembly on a PC-compatible system. The graphics controller that is part of the North Bridge (see the sidebar “The North Bridge”) connects to different types of display devices using several interface standards (see the sidebar “Video Cabling Standards”).
Video Graphics Array (VGA) is the original display standard introduced by IBM, but it’s more of a resolution specification today. VGA refers to a resolution of 640480, whereas newer standards such as eXtended Graphics Array (XGA) and Super Video Graphics Array (SVGA) support higher resolutions of 800¥600 and 1024¥768. Quarter VGA (QVGA) panels having a resolution of 320240 are common on embedded devices, such as handhelds and smart phones.
Figure 12.1 shows the display assembly on a PC-compatible system. The graphics controller that is part of the North Bridge (see the sidebar “The North Bridge”) connects to different types of display devices using several interface standards (see the sidebar “Video Interfacing Standards”).
Video Graphics Array (VGA) is the original display standard introduced by IBM, but it’s more of a resolution specification today. VGA refers to a resolution of 640480, whereas newer standards such as Super Video Graphics Array (SVGA) and eXtended Graphics Array (XGA) support higher resolutions of 800¥600 and 1024¥768, respectively. Quarter VGA (QVGA) panels having a resolution of 320240 are common on embedded devices, such as handhelds and smart phones.
12/3/2008
3 p 357 Consider, for example, the Intel 855 GMCH North Bridge chipset. The FSB controller in the 855 GMCH interfaces with Pentium M processors. The memory controller supports Dual Data Rate (DDR) SDRAM memory chips. The integrated graphics controller lets you connect to display devices using analog VGA, LVDS, or DVI (see the sidebar “Video Cabling Standards”). The 855 GMCH enables you to simultaneously send output to two displays, so you can, for example, dispatch similar or separate information to your laptop’s LCD panel and an external CRT monitor at the same time.
Consider, for example, the Intel 855 GMCH North Bridge chipset. The FSB controller in the 855 GMCH interfaces with Pentium M processors. The memory controller supports Dual Data Rate (DDR) SDRAM memory chips. The integrated graphics controller lets you connect to display devices using analog VGA, LVDS, or DVI (see the sidebar “Video Interfacing Standards”). The 855 GMCH enables you to simultaneously send output to two displays, so you can, for example, dispatch similar or separate information to your laptop’s LCD panel and an external CRT monitor at the same time.
12/3/2008
3 p 357 Video Cabling Standards
Several interfacing standards specify the connection between video controllers and display devices. Display devices and the cabling technologies they use follow:
• An analog display such as a cathode ray tube (CRT) monitor that has a standard VGA connector.
• A digital flat-panel display such as a laptop Thin Film Transistor (TFT) LCD that has a low-voltage differential signaling (LVDS) connector.
• A display monitor that complies with the Digital Visual Interface (DVI) specification. DVI is a standard developed by the Digital Display Working Group (DDWG) for carrying high-quality video. There are three DVI subclasses: digital-only (DVI-D), analog-only (DVI-A), and digital-and-analog (DVI-I).
• A display monitor that complies with the High-Definition Television (HDTV) specification using the High-Definition Multimedia Interface (HDMI). HDMI is a modern digital audio-video cable standard that supports high data rates. Unlike video-only standards such as DVI, HDMI can carry both picture and sound.
Video Interfacing Standards
Several interfacing standards specify the connection between video controllers and display devices. Display devices and the interfacing technologies they use follow:
• An analog display such as a cathode ray tube (CRT) monitor that has a standard VGA connector.
• A digital flat-panel display such as a laptop Thin Film Transistor (TFT) LCD that takes in low-voltage differential signaling (LVDS).
• A display monitor that complies with the Digital Visual Interface (DVI) specification. DVI is a standard developed by the Digital Display Working Group (DDWG) for carrying high-quality video. DVI monitors take in Transition Minimized Differential Signaling (TMDS). There are three DVI subclasses: digital-only (DVI-D), analog-only (DVI-A), and digital-and-analog (DVI-I).
• A display monitor that complies with the High-Definition Television (HDTV) specification using the High-Definition Multimedia Interface (HDMI). HDMI is a modern digital audio-video cable standard that supports high data rates. Unlike video-only standards such as DVI, HDMI can carry both picture and sound.
12/3/2008
3 p 358 In Fig. 12.3, change DVI to TMDS done 12/3/2008
3 p 358 Figure 12.3 shows an embedded device that supports dual display panels: an internal LVDS flat-panel LCD and an external DVI monitor. The internal TFT LCD takes an LVDS connector as input, so an LVDS transmitter chip is used to convert the flat-panel signals to LVDS. An example of an LVDS transmitter chip is DS90C363B from National Semiconductor. The external DVI monitor takes only a DVI connector, so a DVI transmitter is used to convert the 18-bit video signals to DVI-D. An I2C interface is provided so that the device driver can configure the DVI transmitter registers. An example of a DVI transmitter chip is SiI164 from Silicon Image.
Figure 12.3 shows an embedded device that supports dual display panels: an internal LVDS flat-panel LCD and an external DVI monitor. The internal TFT LCD understands LVDS, so an LVDS transmitter chip is used to convert the flat-panel signals to LVDS. An example of an LVDS transmitter chip is DS90C363B from National Semiconductor.The external DVI monitor talks in TMDS, so a DVI trnasmitter chip is used to convert the 18-bit flat panel data signals to TMDS. An I2C interface is provided so that the device driver can configure the DVI transmitter registers. An example of a DVI transmitter chip is SiI164 from Silicon Image.
12/3/2008
3 p 365 Our goal is to develop the video software for this system. Let’s assume that Linux supports the SoC used on this navigation device and that all architecture--dependent interfaces such as DMA are supported by the kernel.
Our goal is to develop the video software for this system. Let’s assume that Linux supports the SoC used on this navigation device and that all architecture--dependent services such as DMA are supported by the kernel.
12/3/2008
3 p 388 The frame buffer core layer and low-level frame buffer drivers reside in the drivers/video/ directory. Generic frame buffer structures are defined in include/linux/fb.h, whereas chipset-specific headers stay inside include/video/. The fbmem driver, drivers/video/fbmem.c, creates the /dev/fbX character devices and is the front end for handling frame buffer ioctl commands issued by user applications.
The intelfb driver, drivers/video/intelfb/*, is the low-level frame buffer driver for several Intel graphics controllers such as the one integrated with the 855 GME North Bridge. The radeonfb driver, drivers/video/aty/*, is the frame buffer driver for -Radeon Mobility AGP graphics hardware from ATI technologies. The source files, drivers/video/*fb.c, are all frame buffer drivers for graphics controllers, including those integrated into several SoCs. You can use drivers/video/skeletonfb.c as the starting point if you are writing a custom low-level frame buffer driver. Look at Documentation/fb/* for more documentation on the frame buffer layer.
The home page of the Linux frame buffer project is www.linux-fbdev.org. This website contains HOWTOs, links to frame buffer drivers and utilities, and pointers to related web pages.
The frame buffer core layer and low-level frame buffer drivers reside in the drivers/video/ directory. Generic frame buffer structures are defined in include/linux/fb.h, whereas chipset-specific headers stay inside include/video/. The fbmem driver drivers/video/fbmem.c, creates the /dev/fbX character devices and is the front end for handling frame buffer ioctl commands issued by user applications.
The intelfb driver drivers/video/intelfb/*, is the low-level frame buffer driver for several Intel graphics controllers such as the one integrated with the 855 GME North Bridge. The radeonfb driver drivers/video/aty/*, is the frame buffer driver for -Radeon Mobility AGP graphics hardware from ATI technologies. The source files drivers/video/*fb.c, are all frame buffer drivers for graphics controllers, including those integrated into several SoCs. You can use drivers/video/skeletonfb.c as the starting point if you are writing a custom low-level frame buffer driver. Look at Documentation/fb/* for more documentation on the frame buffer layer.
The home page of the Linux frame buffer project is www.linux-fbdev.org. This website contains HOWTOs, links to frame buffer drivers and utilities, and pointers to related web pages.
12/3/2008
3 p 395 • The user-space ALSA library, alsa-lib, which provides the libasound.so object. This library eases the job of the ALSA application programmer by offering several canned routines to access ALSA drivers.
• The user-space ALSA library alsa-lib, which provides the libasound.so object. This library eases the job of the ALSA application programmer by offering several canned routines to access ALSA drivers.
12/3/2008
3 p 399 The remove() counterpart of the probe method, mycard_audio_remove(), releases the snd_card from the ALSA framework using snd_card_free().
The remove() counterpart of the probe method mycard_audio_remove(), releases the snd_card from the ALSA framework using snd_card_free().
12/3/2008
3 p 400 struct device *dev; /* Associated hardware
device */
};

3. Connects playback operations with the PCM instance created in Step 2, by calling snd_pcm_set_ops(). The snd_pcm_ops structure specifies these operations for transferring PCM audio to the codec. Listing 13.1 accomplishes this as follows:
struct device *dev; /* Associated hardware
device */
};
The snd_device_new() routine lies at the core of snd_pcm_new() and other similar component instantiation functions.
3. Connects playback operations with the PCM instance created in Step 2, by calling snd_pcm_set_ops(). The snd_pcm_ops structure specifies these operations for transferring PCM audio to the codec. Listing 13.1 accomplishes this as follows:
12/3/2008
3 p 402 The snd_kcontrol structure describes a control element. Our driver uses it as a knob for general volume control. snd_ctl_add() registers an snd_kcontrol element with the ALSA framework. The constituent control methods are invoked when user applications such as alsamixer are executed. In Listing13.1, the snd_kcontrol put() method, mycard_playback_volume_put(), writes requested volume settings to the codec’s VOLUME_REGISTER.
The snd_kcontrol structure describes a control element. Our driver uses it as a knob for general volume control. snd_ctl_add() registers an snd_kcontrol element with the ALSA framework. The constituent control methods are invoked when user applications such as alsamixer are executed. In Listing13.1, the snd_kcontrol put() method mycard_playback_volume_put(), writes requested volume settings to the codec’s VOLUME_REGISTER.
12/3/2008
3 p 433 case READ:
/* Issue Read Sector Command */
outb(READ_SECTOR_CMD, COMMAND_REGISTER);
/* Traverse all requested sectors, byte by byte */
for (i = 0; i < 512*req->nr_sectors; i++) {
/* Wait until the disk is ready. Busy duration should be
in the order of microseconds. Sitting in a tight loop
for simplicity; more intelligence required in the real
world */
while ((status = inb(STATUS_REGISTER)) & BUSY_STATUS);

/* Read data from disk to the buffer associated with the
request */
req->buffer[i] = inb(DATA_REGISTER);
}
good = 1;
break;
case WRITE:
case READ:
/* Issue Read Sector Command */
outb(READ_SECTOR_CMD, COMMAND_REGISTER);
/* Traverse all requested sectors, byte by byte */
for (i = 0; i < 512*req->nr_sectors; i++) {
/* Wait until the disk is ready. Busy duration should be
in the order of microseconds. Sitting in a tight loop
for simplicity; more intelligence required in the real
world */
while ((status = inb(STATUS_REGISTER)) & BUSY_STATUS);

/* Read data from disk to the buffer associated with the
request */
req->buffer[i] = inb(DATA_REGISTER);
}
good = 1;
break;
case WRITE:
12/3/2008
3 p 427 Listing 14.1 contains the driver initialization method, myblkdev_init(), which performs the following steps:
Listing 14.1 contains the driver initialization method myblkdev_init(), which performs the following steps:
12/3/2008
3 p 435 Unlike our sample driver that busy-waits for requested operations to finish, the cpqarray driver implements an interrupt handler, do_ida_intr(), to receive alerts from the hardware upon completion of commands.
Unlike our sample driver that busy-waits for requested operations to finish, the cpqarray driver implements an interrupt handler do_ida_intr(), to receive alerts from the hardware upon completion of commands.
12/3/2008
3 p 479 Change 1R Transceiver to IR Transceiver. done 12/3/2008
3 p 509 Because the kernel finds that the name of the platform driver registered in Listing17.2 matches with that of an already-registered platform device, it invokes the probe method, pda_mtd_probe(), shown in Listing 17.3. This routine
Because the kernel finds that the name of the platform driver registered in Listing17.2 matches with that of an already-registered platform device, it invokes the probe method pda_mtd_probe(), shown in Listing 17.3. This routine
12/3/2008
3 p 516 The MTD subsystem provides a block driver called mtdblock that emulates a hard disk over flash memory. You can put any filesystem, say EXT2, over the emulated flash disk. Mtdblock hides complicated flash access procedures (such as preceding a write with an erase of the corresponding sector) from the filesystem. Device nodes created by mtdblock are named /dev/mtdblock/X, where X is the partition number. To create an EXT2 filesystem on the pda_fs partition of the handheld, shown in Figure 17.2, do the following:
The MTD subsystem provides a block driver called mtdblock that emulates a hard disk over flash memory. You can put any filesystem, say EXT2, over the emulated flash disk. Mtdblock hides complicated flash access procedures (such as preceding a write with an erase of the corresponding sector) from the filesystem. Device nodes created by mtdblock are named /dev/mtdblock/X, where X is the partition number. To create an EXT2 filesystem on the pda_fs partition of the handheld shown in Figure 17.2, do the following:
12/3/2008
3 p 534 PowerPC PowerPC chips used on embedded devices include SoCs such as IBM’s 405LP and the 440GP, and Motorola’s MPC7xx and MPC8xx. Bootloaders such as U-Boot (http://-sourceforge.net/projects/u-boot/), SLOF, and PIBS boot Linux on PowerPC-based hardware.
PowerPC PowerPC chips used on embedded devices include SoCs such as IBM’s 405LP and the 440GP, and Motorola’s MPC7xx and MPC8xx. Bootloaders such as U-Boot (http://-sourceforge.net/projects/u-boot/), SLOF, and PIBS, boot Linux on PowerPC-based hardware.
12/3/2008
3 p 541 As you saw in Chapter 13, “Audio Drivers,” an audio codec converts digital audio data to analog sound signals for playback via speakers and performs the reverse operation for recording through a microphone. The codec’s connection with the CPU depends on the digital audio interface supported by the embedded controller. The usual way to communicate with a codec is via buses, such as AC’97 or I2S.
As you saw in Chapter 13, “Audio Drivers,” an audio codec converts digital audio data to analog sound signals for playback via speakers and performs the reverse operation for recording through a microphone. The codec’s connection with the CPU depends on the digital audio interface supported by the embedded controller. The usual way to communicate with a codec is via buses such as AC’97 or I2S.
12/3/2008
3 p 549 A multimeter and an oscilloscope are worthy additions to your embedded debugging toolkit. As an illustration, let’s consider an example situation involving the I2C RTC as shown in Figure 8.3 of Chapter 8. That figure is reproduced there with a multimeter/scope attached to probe points of interest. Consider this scenario: You have written an I2C client driver for this RTC chip as described in the section “Device Example: Real Time Clock” in Chapter 8. A multimeter and an oscilloscope are worthy additions to your embedded debugging toolkit. As an illustration, let’s consider an example situation involving the I2C RTC shown in Figure 8.3 of Chapter 8. Figure 18.4 reproduces it with a multimeter/scope attached to probe points of interest. Consider this scenario: You have written an I2C client driver for this RTC chip as described in the section “Device Example: Real Time Clock” in Chapter 8. 12/4/2008
3 p 585 Advanced Configuration and Power Interface (ACPI) is a power-management specification that replaces earlier standards such as Advanced Power Management (APM). ACPI is responsible for transitioning the system between power states. It also has the task of interfacing with devices and sensors connected to the EC. Such devices are called ACPI devices, and memory devoted to handle them is called ACPI space.
Advanced Configuration and Power Interface (ACPI) is a power-management specification that replaces earlier standards such as Advanced Power Management (APM). ACPI is responsible for transitioning the system between power states. It also has the task of interfacing with devices and sensors connected to the EC. Such devices are called ACPI devices, and memory devoted to handle them is called ACPI space.
12/4/2008
3 p 586 6. The acpid daemon, which is the policy enabler for ACPI events. It listens on /proc/acpi/events for power-management events reported by the kernel. When you press the power button or when a thermal trip occurs, the kernel ACPI driver dispatches an event to user space via /proc/acpi/events. Acpid reads this, passes it through configuration scripts present in /etc/acpi/events/ and takes specified actions. Assume that you want to execute a specific program (/bin/lidhandler) when your laptop’s lid button is pressed. For this, add the following to /etc/acpi/events/acpi_handler.sh:
6. The acpid daemon, which is the policy enabler for ACPI events. It listens on /proc/acpi/events for power-management events reported by the kernel. When you press the power button or when a thermal trip occurs, the kernel ACPI driver dispatches an event to user space via /proc/acpi/events. The acpid daemon reads this, passes it through configuration scripts present in /etc/acpi/events/ and takes specified actions. Assume that you want to execute a specific program (/bin/lidhandler) when your laptop’s lid button is pressed. For this, add the following to /etc/acpi/events/acpi_handler.sh:
12/4/2008
3 p 588 Look at drivers/net/tokenring/skisa.c for a sample ISA driver for a Token Ring card. The IBM Token Ring driver, drivers/net/tokenring/ibmtr.c, supports ISA, PnP, and MCA form factors of IBM Token Ring hardware. The 3COM Ethernet driver, drivers/net/3c509.c, drives MCA, PnP, and EISA form factors of a 3COM Ethernet card. The kernel provides core routines for the use of PnP, EISA, and MCA drivers. These implementations live in drivers/pnp/, drivers/eisa/, and drivers/mca/, respectively.
Look at drivers/net/tokenring/skisa.c for a sample ISA driver for a Token Ring card. The IBM Token Ring driver drivers/net/tokenring/ibmtr.c, supports ISA, PnP, and MCA form factors of IBM Token Ring hardware. The 3COM Ethernet driver drivers/net/3c509.c, drives MCA, PnP, and EISA form factors of a 3COM Ethernet card. The kernel provides core routines for the use of PnP, EISA, and MCA drivers. These implementations live in drivers/pnp/, drivers/eisa/, and drivers/mca/, respectively.
12/4/2008
3 p 589 • A FireWire core that provides services to both previously mentioned.
• A FireWire core that provides services to both the above.
12/4/2008
3 p 593 Linux supports iSCSI via a kernel driver, drivers/scsi/iscsi_tcp.c, and a user-space daemon called iscsid. The home page of the Linux-iSCSI project is at http://linux-iscsi.sourceforge.net. Linux supports iSCSI via a kernel driver drivers/scsi/iscsi_tcp.c, and a user-space daemon called iscsid. The home page of the Linux-iSCSI project is at http://linux-iscsi.sourceforge.net. 12/4/2008
3 p 658 The kernel system call trap in arch/x86/kernel/entry_32.S saves all register contents to stack, so the real system calls see their arguments on stack, even though user-space code passes them in CPU registers. To ensure that system call routines expect arguments on stack, they are all tagged with the GCC attribute, asmlinkage. Note that asmlinkage has nothing to do with the asm (or __asm__) that is used to declare inline assembly.
The kernel system call trap in arch/x86/kernel/entry_32.S saves all register contents to stack, so the real system calls see their arguments on stack, even though user-space code passes them in CPU registers. To ensure that system call routines expect arguments on stack, they are all tagged with the GCC attribute, asmlinkage. Note that asmlinkage has nothing to do with asm (or __asm__) that is used to declare inline assembly.
12/4/2008
3 p 662 Parts of the x86 kernel, such as the video frame buffer driver (vesafb) and Advanced Power Management (APM), explicitly use BIOS services to accomplish certain functions. Parts of the x86 kernel, such as the video frame buffer driver (vesafb) and Advanced Power Management (APM), explicitly use BIOS services to accomplish certain functions. 12/4/2008
3 p 663 In the listing, 0xe820 is the function number specified in the AX register before invoking int 0x15 to procure the memory map. If you look at the BIOS call definition for int 0x15, function 0xe820 (the full list is available at http:// lrs.fmi.uni-passau.de/support/doc/interrupt-57/INT.HTM), you will see that the BIOS writes the current element of the memory map in a buffer pointed to by the DI register. In the listing, 0xe820 is the function number specified in the AX register before invoking int 0x15 to procure the memory map. If you look at the BIOS call definition for int 0x15, function 0xe820, you will see that the BIOS writes the current element of the memory map in a buffer pointed to by the DI register. 12/4/2008
3 p 666 To do this, kapmd needs to know the protected mode entry segment address and offset. These are obtained from the real mode kernel during boot using the int 0x15, function 0x5303 BIOS service.
To do this, kapmd needs to know the protected mode entry segment address and offset. These are obtained from the real mode kernel during boot using the int 0x15, function 0x5303 BIOS service.
12/4/2008
3 p 670 The example code in Listing C.1 uses a procfs file named /proc/readme to export these strings to user space. When a user reads this file, the procfs read() method, readme_proc(), gets invoked. The example code in Listing C.1 uses a procfs file named /proc/readme to export these strings to user space. When a user reads this file, the procfs read() method readme_proc(), gets invoked. 12/4/2008
3 p 672 The second argument, start, is used to aid the implementation of procfs files larger than a page. The use of this parameter will get clear when we look at the example in Listing C.2. The second argument start, is used to aid the implementation of procfs files larger than a page. The use of this parameter will get clear when we look at the example in Listing C.2. 12/4/2008
3 p 135 The first argument to aio_read()/aio_write() describes the AIO operation, and the second argument is an array of iovecs. The latter is the principal data structure used by the vector functions and contains the addresses and lengths of buffers that hold the data. In fact, this mechanism is the user space equivalent of scatter-gather DMA discussed in Chapter 10. Look at include/linux/uio.h for the definition of iovecs and at drivers/net/tun.c1 for an example implementation of vectored char driver methods.

1Discussed in the sidebar “TUN/TAP Driver” in Chapter 15, “Network Interface Cards.”
The first argument to aio_read()/aio_write() describes the AIO operation, and the second argument is an array of iovecs. The latter is the principal data structure used by the vector functions and contains the addresses and lengths of buffers that hold the data. In fact, this mechanism is the user space equivalent of scatter-gather DMA discussed in Chapter 10. Look at include/linux/uio.h for the definition of iovecs and at drivers/net/tun.c2 for an example implementation of vectored char driver methods.

2Discussed in the sidebar “TUN/TAP Driver” in Chapter 15, “Network Interface Cards.”
12/5/2008
3 p 142 If there is no change in the data condition, the poll()method returns 0. If the driver is ready to send at least one byte of data to the application, it returns POLLIN|POLLRDNORM. If the driver is ready to accept at least a byte of data from the application, it returns POLLOUT|POLLWRNORM.2

2The full list of return codes is defined in include/asm-generic/poll.h. Some of them are used only by the networking stack.
If there is no change in the data condition, the poll()method returns 0. If the driver is ready to send at least one byte of data to the application, it returns POLLIN|POLLRDNORM. If the driver is ready to accept at least a byte of data from the application, it returns POLLOUT|POLLWRNORM.3

3The full list of return codes is defined in include/asm-generic/poll.h. Some of them are used only by the networking stack.
12/5/2008
3 p 144 • Implements the SIGIO signal handler, xf86SIGIO(), as per its code architecture and installs it using the sigaction() system call. When the underlying input device driver detects a change in data status, it dispatches SIGIO to registered requesters and this triggers execution of xf86SIGIO().3

3If your signal handler services asynchronous events from multiple devices, you will need additional mechanisms, such as a select() call inside the handler, to figure out the identity of the device responsible for the event.
• Implements the SIGIO signal handler, xf86SIGIO(), as per its code architecture and installs it using the sigaction() system call. When the underlying input device driver detects a change in data status, it dispatches SIGIO to registered requesters and this triggers execution of xf86SIGIO().4

4If your signal handler services asynchronous events from multiple devices, you will need additional mechanisms, such as a select() call inside the handler, to figure out the identity of the device responsible for the event.
12/5/2008
3 p 160 A watchdog’s function is to return an unresponsive system to operational state. It does this by periodically checking the system’s pulse and issuing a reset4 if it can’t detect

4A watchdog may issue audible beeps rather than a system reset. An example scenario is when a timeout occurs due to a power supply problem, assuming that the watchdog circuit is backed up using a battery or a super capacitor.
A watchdog’s function is to return an unresponsive system to operational state. It does this by periodically checking the system’s pulse and issuing a reset5 if it can’t detect

5A watchdog may issue audible beeps rather than a system reset. An example scenario is when a timeout occurs due to a power supply problem, assuming that the watchdog circuit is backed up using a battery or a super capacitor.
12/5/2008
3 p 161 Strobing the watchdog is usually done from user space because the goal of having a watchdog is to detect and respond to both application and kernel hangs. A critical application5 such as the graphics engine in Listing 5.10 opens the watchdog driver in Listing 5.9 and periodically writes to it.

5If you need to monitor the health of several applications, you may implement a multiplexer in the watchdog device driver. If any one of the processes that open the driver becomes unresponsive, the watchdog attempts to self-correct the system.
Strobing the watchdog is usually done from user space because the goal of having a watchdog is to detect and respond to both application and kernel hangs. A critical application6 such as the graphics engine in Listing 5.10 opens the watchdog driver in Listing 5.9 and periodically writes to it.

6If you need to monitor the health of several applications, you may implement a multiplexer in the watchdog device driver. If any one of the processes that open the driver becomes unresponsive, the watchdog attempts to self-correct the system.
12/5/2008
3 p 273 The Point-to-Point Protocol (PPP) allows networking protocols such as TCP/IP to run over a serial link. In the context of Figure 9.5, PPP gets TCP/IP applications running over GPRS and GSM dialup. The PPP daemon pppd, attaches over virtual serial ports emulated by serial_cs. The PPP kernel modules—ppp_generic, ppp_async, and slhc—have to be loaded for pppd to work. Invoke pppd as follows:
The Point-to-Point Protocol (PPP) allows networking protocols such as TCP/IP to run over a serial link. In the context of Figure 9.5, PPP gets TCP/IP applications running over GPRS and GSM dialup. The PPP daemon pppd, attaches over virtual serial ports emulated by serial_cs. The PPP kernel modules—ppp_generic, ppp_async, and slhc—have to be loaded for pppd to work. Invoke pppd as follows:
12/5/2008
3 p 13 bash> cd /path/to/module-source/
bash> echo "obj-m += mymodule.ko" > Makefile
bash> make –C /path/to/kernel-sources/ M=`pwd` modules
make: Entering directory '/path/to/kernel-sources'
Building modules, stage 2.
MODPOST
CC /path/to/module-sources/mymodule.mod.o
LD [M] /path/to/module-sources/mymodule.ko
make: Leaving directory '/path/to/kernel-sources'
bash> insmod ./mymodule.ko
bash> cd /path/to/module-source/
bash> echo "obj-m += mymodule.o" > Makefile
bash> make –C /path/to/kernel-sources/ M=`pwd` modules
make: Entering directory '/path/to/kernel-sources'
Building modules, stage 2.
MODPOST
CC /path/to/module-sources/mymodule.mod.o
LD [M] /path/to/module-sources/mymodule.ko
make: Leaving directory '/path/to/kernel-sources'
bash> insmod ./mymodule.ko
12/5/2008
3 pxiv This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v 1.0 or later (the latest version is presently avaiable at http://www.opencontent.org/openpub/).

The code in this book may be distributed only subject to the terms and conditions set forth in the Open Publication License, v 1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/).
3/18/2009
3 p 104 Use udevinfo to collect device information:
bash> udevinfo -a -p /sys/block/sr0
...
looking at the device chain at
‘/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4':
BUS=»usb»
ID=»1-4»
SYSFS{bConfigurationValue}=»1»
...
SYSFS{idProduct}=»0701»
Use udevinfo to collect device information:
bash> udevinfo -a -p /sys/block/sr0
...
looking at the device chain at
‘/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4':
BUS=="usb"
ID=="1-4"
SYSFS{bConfigurationValue}=="1"
...
SYSFS{idProduct}=="0701"
4/7/2009
3 p 105 SYSFS{idVendor}=»05e3»
SYSFS{manufacturer}=»Genesyslogic»
SYSFS{maxchild}=»0»
SYSFS{product}=»USB Mass Storage Device»
...

bash> udevinfo -a -p /sys/block/sr1
...
looking at the device chain at
‘/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-3':
BUS=»usb»
ID=»1-3»
SYSFS{bConfigurationValue}=»2»
...
SYSFS{idProduct}=»0302»
SYSFS{idVendor}=»0dbf»
SYSFS{manufacturer}=»Addonics»
SYSFS{maxchild}=»0»
SYSFS{product}=»USB to IDE Cable»
...
Next, let’s use the product information gleaned to identify the devices and add udev naming rules. Create a file called /etc/udev/rules.d/40-cdvd.rules and add the following rules to it:
BUS="usb", SYSFS{idProduct}="0701", SYSFS{idVendor}="05e3",
KERNEL="sr[0-9]*", NAME="%k", SYMLINK="usbdvd"

BUS="usb", SYSFS{idProduct}="0302", SYSFS{idVendor}="0dbf",
KERNEL="sr[0-9]*", NAME="%k", SYMLINK="usbcdrw"
SYSFS{idVendor}=="05e3"
SYSFS{manufacturer}=="Genesyslogic"
SYSFS{maxchild}=="0"
SYSFS{product}=="USB Mass Storage Device"
...

bash> udevinfo -a -p /sys/block/sr1
...
looking at the device chain at
‘/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-3':
BUS=="usb"
ID=="1-3"
SYSFS{bConfigurationValue}=="2"
...
SYSFS{idProduct}=="0302"
SYSFS{idVendor}=="0dbf"
SYSFS{manufacturer}=="Addonics"
SYSFS{maxchild}=="0"
SYSFS{product}=="USB to IDE Cable"
...
Next, let’s use the product information gleaned to identify the devices and add udev naming rules. Create a file called /etc/udev/rules.d/40-cdvd.rules and add the following rules to it:
BUS=="usb", SYSFS{idProduct}=="0701", SYSFS{idVendor}=="05e3",
KERNEL=="sr[0-9]*", NAME="%k", SYMLINK="usbdvd"

BUS=="usb", SYSFS{idProduct}=="0302", SYSFS{idVendor}=="0dbf",
KERNEL=="sr[0-9]*", NAME="%k", SYMLINK="usbcdrw"
4/7/2009
3 p 127 KERNEL="cmos[0-1]*", NAME="cmos/%n"
KERNEL=="cmos[0-1]*", NAME="cmos/%n"
4/7/2009
3 p 240 KERNEL:"eeprom[0-1]*", NAME="eep/%n"
KERNEL=="eeprom[0-1]*", NAME="eep/%n"
4/7/2009
3 p 350 Ensure that you have enabled debugfs (CONFIG_DEBUG_FS) and usbmon (CONFIG_USB_MON) support in your kernel. This is a snapshot of usbmon output while copying a file from the disk:
Ensure that you have enabled debugfs (CONFIG_DEBUG_FS) and usbmon (CONFIG_USB_MON) support in your kernel. This is a snapshot of usbmon output while copying a file from the disk:
4/7/2009
3 p 459 • Minimizing the number of instructions in the main data path is a key criterion while designing drivers for fast NICs. Consider a 1Gbps Ethernet adapter with 1MB of on-board memory. At line rate, the card memory can hold up to 8 milliseconds of received data. This directly translates to the maximum allowable instruction path length. Within this path length, incoming packets have to be reassembled, DMAed to memory, processed by the driver, protected from concurrent access, and delivered to higher layer protocols.
• Minimizing the number of instructions in the main data path is a key criterion while designing drivers for fast NICs. Consider a 1Gbps Ethernet adapter with 1MB of on-board memory. At line rate, the card memory can hold up to 8 milliseconds of received data. This directly translates to the maximum allowable instruction path length. Within this path length, incoming packets have to be reassembled, DMA-ed to memory, processed by the driver, protected from concurrent access, and delivered to higher layer protocols.
4/7/2009
3 p 524 The Linux-MTD project page www.linux-mtd.infradead.org has FAQs, various pieces of documentation, and a Linux-MTD JFFS HOWTO that provides insights into JFFS2 design. The linux-mtd mailing list is the place to discuss questions related to MTD device drivers. Look at /http://lists.infradead.org/pipermail/linux-mtd/ for the mailing list archives.
The Linux-MTD project page www.linux-mtd.infradead.org has FAQs, various pieces of documentation, and a Linux-MTD JFFS HOWTO that provides insights into JFFS2 design. The linux-mtd mailing list is the place to discuss questions related to MTD device drivers. Look at http://lists.infradead.org/pipermail/linux-mtd/ for the mailing list archives.
4/7/2009
3 p 528 • The Linux community has a lot more experience on the x86 platform, so you are less likely to get instant online help from experts if you working on embedded computers.
• The Linux community has a lot more experience on the x86 platform, so you are less likely to get instant online help from experts if you are working on embedded computers.
4/7/2009
3 p 549 The RTC buffers the clock for its use and makes it available on an output pin for free. This pin, CLK_OUT, feeds the clock to the processor. Connect an oscilloscope (or a multimeter that can measure frequency) between CLK_OUT and ground to verify the processor clock frequency. As you can see in Figure 18.4, the scope reads 1KHz rather than the expected 32KHz! What could be wrong here?
The RTC buffers the clock for its use and makes it available on an output pin for free. This pin CLK_OUT, feeds the clock to the processor. Connect an oscilloscope (or a multimeter that can measure frequency) between CLK_OUT and ground to verify the processor clock frequency. As you can see in Figure 18.4, the scope reads 1KHz rather than the expected 32KHz! What could be wrong here?
4/7/2009
3 p 617 When Listing 21.4 invokes register_jprobes() to register the jprobe, a kprobe is inserted at the beginning of printk(). When this probe is hit, Kprobes replaces the saved return address with that of the registered jprobe handler, jprintk(). It then copies a portion of the stack and returns, thus passing control to jprintk() with printk()’s argument list. When jprintk() calls jprobe_return(), the original call state is restored, and printk() continues to execute normally.
When Listing 21.4 invokes register_jprobes() to register the jprobe, a kprobe is inserted at the beginning of printk(). When this probe is hit, Kprobes replaces the saved return address with that of the registered jprobe handler jprintk(). It then copies a portion of the stack and returns, thus passing control to jprintk() with printk()’s argument list. When jprintk() calls jprobe_return(), the original call state is restored, and printk() continues to execute normally.
4/7/2009
3 p 639 Another related option, CONFIG_4KSTACKS, lets you set the kernel stack size to 4KB rather than 8KB.
Another related option CONFIG_4KSTACKS, lets you set the kernel stack size to 4KB rather than 8KB.
4/7/2009
3 p 646 export INSTALL_MOD_PATH=»$TARGET_DIRECTORY/modules»
make modules_install
export INSTALL_MOD_PATH=”$TARGET_DIRECTORY/modules”
make modules_install
4/7/2009
3 p 663 In the listing, 0xe820 is the function number specified in the AX register before invoking int 0x15 to procure the memory map. If you look at the BIOS call definition for int 0x15, function 0xe820, you will see that the BIOS writes the current element of the memory map in a buffer pointed to by the DI register. In Listing B.1, DI points to the offset in the zero page where the memory map is to be stored (boot_params.e820_map). In the listing, 0xe820 is the function number specified in the AX register before invoking int 0x15 to procure the memory map. If you look at the BIOS call definition for int 0x15, function 0xe820 (the full list is available at http://lrs.fim.uni-passau.de/support/doc/interrupt-57/INT.HTM), you will see that the BIOS writes the current element of the memory map in a buffer pointed to by the DI register. In Listing B.1, DI points to the offset in the zero page where the memory map is to be stored (boot_params.e820_map). 4/7/2009
3 p31 Access user space virtual memory Access user-space virtual memory 4/16/2009
3 p110 With a udev-039 package and a 2.6.9 kernel, when the kernel detects a hotplug event, it invokes the user space helper registered with /proc/sys/kernel/hotplug. With a udev-039 package and a 2.6.9 kernel, when the kernel detects a hotplug event, it invokes the user-space helper registered with /proc/sys/kernel/hotplug. 4/16/2009
3 p114 Power management also features participation from user space daemons, utilities, configuration files, and boot firmware. Power management also features participation from user-space daemons, utilities, configuration files, and boot firmware. 4/16/2009
3 p139 Sensing data availability is not relevant for the simple CMOS memory device discussed previously, so let’s take a few usage scenarios from a popular user space application: the X Windows server.
Sensing data availability is not relevant for the simple CMOS memory device discussed previously, so let’s take a few usage scenarios from a popular user-space application: the X Windows server.
4/16/2009
3 p157 The RTC API guarantees that user space tools are independent of the underlying platform and the RTC chip. The RTC API guarantees that user-space tools are independent of the underlying platform and the RTC chip. 4/16/2009
3 p167 One example is the generic SCSI driver drivers/scsi/sg.c used to implement user space device drivers for SCSI scanners and CD drives. One example is the generic SCSI driver drivers/scsi/sg.c used to implement user-space device drivers for SCSI scanners and CD drives. 4/16/2009
3 p204 N_TCH gets bound to the low-level serial driver when a user space program opens the serial port connected to the touch controller. N_TCH gets bound to the low-level serial driver when a user-space program opens the serial port connected to the touch controller. 4/16/2009
3 p228 This driver is, however, scheduled for removal from the mainline kernel in favor of the user space tslib library. This driver is, however, scheduled for removal from the mainline kernel in favor of the user-space tslib library. 4/16/2009
3 p253 Currently there is no support for user space SPI drivers à la i2c-dev. Currently there is no support for user-space SPI drivers à la i2c-dev. 4/16/2009
3 p260 Earlier kernels relied on a user space daemon called cardmgr to support hotplugging, but the new PCMCIA implementation handles hotplug using udev, just as other bus subsystems do. Earlier kernels relied on a user-space daemon called cardmgr to support hotplugging, but the new PCMCIA implementation handles hotplug using udev, just as other bus subsystems do. 4/16/2009
3 p409 To understand how the user space alsa-lib library interacts with kernel space ALSA drivers, let’s write a simple application that sets the volume gain of the MP3 player. To understand how the user-space alsa-lib library interacts with kernel space ALSA drivers, let’s write a simple application that sets the volume gain of the MP3 player. 4/16/2009
3 p446 The mechanism for registering get_wireless_stats() for the benefit of WiFi-aware user space utilities is discussed in the section “WiFi” in the next chapter.
Configuration
NIC drivers need to support user space tools that are responsible for setting and getting device parameters.
The mechanism for registering get_wireless_stats() for the benefit of WiFi-aware user-space utilities is discussed in the section “WiFi” in the next chapter.
Configuration
NIC drivers need to support user-space tools that are responsible for setting and getting device parameters.
4/16/2009
3 p459 Linux-ATM is an experimental collection of kernel drivers, user space utilities, and daemons. Linux-ATM is an experimental collection of kernel drivers, user-space utilities, and daemons. 4/16/2009
3 p469 Figure 16.2 shows how BlueZ maps Bluetooth protocol layers to kernel modules, kernel threads, user space daemons, configuration tools, utilities, and libraries. Figure 16.2 shows how BlueZ maps Bluetooth protocol layers to kernel modules, kernel threads, user-space daemons, configuration tools, utilities, and libraries. 4/16/2009
3 p524 The Linux-MTD project page www.linux-mtd.infradead.org has FAQs, various pieces of documentation, and a Linux-MTD JFFS HOWTO that provides insights into JFFS2 design. The Linux-MTD project page www.linux-mtd.infradead.org has FAQs, various pieces of documentation, and a paper that provides insights into JFFS2 design. 4/16/2009
3 p529 The SPI subsystem on the kernel is not as mature as, say, the serial layer. The SPI subsystem in the kernel is not as mature as, say, the serial layer. 4/16/2009
3 p553 In this chapter, the term user space driver (or user mode driver) is used in a generic sense that does not strictly conform to the semantics of a driver implied thus far in the book.


The 2.6 kernel overhauled a subsystem that is of special interest to user space drivers.
In this chapter, the term user-space driver (or user mode driver) is used in a generic sense that does not strictly conform to the semantics of a driver implied thus far in the book.


The 2.6 kernel overhauled a subsystem that is of special interest to user-space drivers.
4/16/2009
3 p570 Listing 19.6 implements a skeletal user space driver for the digital camera using an oft-used libusb programming template. The camera’s vendor ID (0x04b0) and device ID (0x0205) are obtained from the /proc/bus/usb/devices output shown previously.
Listing 19.6A Skeletal User Space USB Driver Using libusb
Listing 19.6 implements a skeletal user-space driver for the digital camera using an oft-used libusb programming template. The camera’s vendor ID (0x04b0) and device ID (0x0205) are obtained from the /proc/bus/usb/devices output shown previously.
Listing 19.6A Skeletal User-Space USB Driver Using libusb
4/16/2009
3 p572 This file contains user space equivalents for all kernel space I2C access functions listed in Table 8.1 of Chapter 8.
Listing 19.7A User Space I2C/SMBus Driver
This file contains user-space equivalents for all kernel space I2C access functions listed in Table 8.1 of Chapter 8.
Listing 19.7A User-Space I2C/SMBus Driver
4/17/2009
3 p574 The SCSI generic implementation is in drivers/scsi/sg.c, and drivers/usb/core/devio.c is responsible for supporting user space USB drivers. The SCSI generic implementation is in drivers/scsi/sg.c, and drivers/usb/core/devio.c is responsible for supporting user-space USB drivers. 4/17/2009
3 p125 unregister_chrdev_region(cmos_dev_number), NUM_CMOS_BANKS); unregister_chrdev_region((cmos_dev_number), NUM_CMOS_BANKS); 4/17/2009
3 p372 DirectFB (www.directfb.org) is a library built on top of the frame buffer interface that provides a simple window manager framework and hooks for hardware graphics acceleration and virtual interfaces that allow coexistence of multiple frame buffer applications. DirectFB (www.directfb.org) is a library built on top of the frame buffer interface that provides a simple window manager framework, hooks for hardware graphics acceleration, and virtual interfaces that allow coexistence of multiple frame buffer applications. 4/17/2009
3 piv This material may be distributed only subject to the terms and conditions set forth in the Open Publication License v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). The code in this book may be redistributed only subject to the terms and conditions set forth in the GNU General Public License version 2 (GPLv2) (presently available at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt). 4/21/2009