From 77ba6298b3a1831b098e7c529b22950d0d7e06d3 Mon Sep 17 00:00:00 2001 From: gferg <> Date: Fri, 27 May 2005 17:04:12 +0000 Subject: [PATCH] updated --- LDP/guide/docbook/lkmpg/2.6/00-Forward.sgml | 23 --- .../docbook/lkmpg/2.6/01-Introduction.sgml | 79 ++++---- .../docbook/lkmpg/2.6/02-HelloWorld.sgml | 170 ++++++++++-------- .../lkmpg/2.6/04-CharacterDeviceFiles.sgml | 8 + .../lkmpg/2.6/05-TheProcFileSystem.sgml | 167 +++++++++++++++-- .../lkmpg/2.6/06-UsingProcForInput.sgml | 84 +-------- .../lkmpg/2.6/07-TalkingToDeviceFiles.sgml | 2 +- .../docbook/lkmpg/2.6/08-SystemCalls.sgml | 15 +- .../lkmpg/2.6/09-BlockingProcesses.sgml | 35 +++- .../lkmpg/2.6/10-ReplacingPrintks.sgml | 10 +- .../docbook/lkmpg/2.6/11-SchedulingTasks.sgml | 31 +--- .../lkmpg/2.6/12-InterruptHandlers.sgml | 49 ++--- .../lkmpg/2.6/A1-ChangesBet20And22.sgml | 97 ++-------- .../lkmpg/2.6/A2-WhereToGoFromHere.sgml | 3 + .../2.6/lkmpg-examples/02-HelloWorld/Makefile | 6 + .../lkmpg-examples/02-HelloWorld/Makefile.1 | 5 + .../lkmpg-examples/02-HelloWorld/Makefile.2 | 6 + .../lkmpg-examples/02-HelloWorld/hello-1.c | 6 +- .../lkmpg-examples/02-HelloWorld/hello-2.c | 6 +- .../lkmpg-examples/02-HelloWorld/hello-3.c | 6 +- .../lkmpg-examples/02-HelloWorld/hello-4.c | 10 +- .../lkmpg-examples/02-HelloWorld/hello-5.c | 31 +++- .../2.6/lkmpg-examples/02-HelloWorld/start.c | 2 +- .../2.6/lkmpg-examples/02-HelloWorld/stop.c | 2 +- .../04-CharacterDeviceFiles/Makefile | 11 ++ .../04-CharacterDeviceFiles/chardev.c | 33 ++-- .../05-TheProcFileSystem/Makefile | 8 +- .../06-UsingProcForInput/Makefile | 6 + .../06-UsingProcForInput/procfs.c | 2 + .../07-TalkingToDeviceFiles/Makefile | 12 ++ .../07-TalkingToDeviceFiles/chardev.c | 30 ++-- .../lkmpg-examples/08-SystemCalls/Makefile | 6 + .../lkmpg-examples/08-SystemCalls/syscall.c | 24 +-- .../09-BlockingProcesses/Makefile | 9 + .../09-BlockingProcesses/sleep.c | 23 ++- .../10-ReplacingPrintks/Makefile | 6 + .../11-SchedulingTasks/Makefile | 6 + .../lkmpg-examples/11-SchedulingTasks/sched.c | 34 ++-- .../12-InterruptHandlers/Makefile | 6 + .../12-InterruptHandlers/intrpt.c | 2 +- LDP/guide/docbook/lkmpg/2.6/lkmpg.sgml | 44 +++-- 41 files changed, 622 insertions(+), 493 deletions(-) diff --git a/LDP/guide/docbook/lkmpg/2.6/00-Forward.sgml b/LDP/guide/docbook/lkmpg/2.6/00-Forward.sgml index 51f8a89e..4e3fba8a 100644 --- a/LDP/guide/docbook/lkmpg/2.6/00-Forward.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/00-Forward.sgml @@ -34,29 +34,6 @@ - + diff --git a/LDP/guide/docbook/lkmpg/2.6/04-CharacterDeviceFiles.sgml b/LDP/guide/docbook/lkmpg/2.6/04-CharacterDeviceFiles.sgml index 2cdc75b9..23bb5bb2 100644 --- a/LDP/guide/docbook/lkmpg/2.6/04-CharacterDeviceFiles.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/04-CharacterDeviceFiles.sgml @@ -240,6 +240,14 @@ int register_chrdev(unsigned int major, const char *name, struct file_operations use LKMPG version 2.4.x for kernels 2.4.x, use LKMPG version 2.6.x for kernels 2.6.x and so on. Also make sure that you always use current, up to date versions of both, kernel and guide. + + Update: What we've said above was true for kernels up to and including 2.6.10. You might already + have noticed that recent kernels look different. In case you haven't they look like 2.6.x.y now. + The meaning of the first three items basically stays the same, but a subpatchlevel has been added and will + indicate security fixes till the next stable patchlevel is out. So people can choose between a stable + tree with security updates and use the latest kernel as developer tree. + Search the kernel mailing list archives if you're interested in the full story. + diff --git a/LDP/guide/docbook/lkmpg/2.6/05-TheProcFileSystem.sgml b/LDP/guide/docbook/lkmpg/2.6/05-TheProcFileSystem.sgml index 148fcc10..6e927e6e 100644 --- a/LDP/guide/docbook/lkmpg/2.6/05-TheProcFileSystem.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/05-TheProcFileSystem.sgml @@ -3,23 +3,25 @@ /proc filesystem filesystem/proc - In Linux there is an additional mechanism for the kernel and kernel modules to send information to processes --- the + + In Linux, there is an additional mechanism for the kernel and kernel modules to send information to processes --- the /proc file system. Originally designed to allow easy access to information about processes (hence the name), it is now used by every bit of the kernel which has something interesting to report, such as - /proc/modules which has the list of modules and /proc/meminfo which has memory usage - statistics. + /proc/modules which provides the list of modules and /proc/meminfo + which stats memory usage statistics. + /proc/modules /proc/meminfo - The method to use the proc file system is very similar to the one used with device drivers --- you create a structure + The method to use the proc file system is very similar to the one used with device drivers --- a structure is created with all the information needed for the /proc file, including pointers to any handler functions (in our case there is only one, the one called when somebody attempts to read from the /proc file). Then, init_module registers the structure with the kernel and cleanup_module unregisters it. The reason we use proc_register_dynamicIn version 2.0, in version 2.2 this is done - for us automatically if we set the inode to zero. is because we don't want to determine the inode number + automatically if we set the inode to zero. is because we don't want to determine the inode number used for our file in advance, but to allow the kernel to determine it to prevent clashes. Normal file systems are located on a disk, rather than just in memory (which is where /proc is), and in that case the inode number is a pointer to a disk location where the file's index-node (inode for short) is located. The inode contains @@ -30,19 +32,160 @@ proc_register inode - Because we don't get called when the file is opened or closed, there's no where for us to put - try_module_get and try_module_put in this module, and if the file is opened and - then the module is removed, there's no way to avoid the consequences. In the next chapter we'll see a harder to implement, but - more flexible, way of dealing with /proc files which will allow us to protect against - this problem as well. + + Because we don't get called when the file is opened or closed, there's nowhere for us to put + try_module_get and try_module_put in this module, and if + the file is opened and then the module is removed, there's no way to avoid the consequences. + + + Here a simple example showing how to use a /proc file. This is the HelloWorld for the /proc filesystem. + There are three parts: create the file /proc/helloworld in the function init_module, + return a value (and a buffer) when the file /proc/helloworld is read in the callback + function procfs_read, and delete the file /proc/helloworld + in the function cleanup_module. + + + + The /proc/helloworld is created when the module is loaded with the function + create_proc_entry. The return value is a 'struct proc_dir_entry *', and it + will be used to configure the file /proc/helloworld (for example, the owner of this file). + A null return value means that the creation has failed. + + + + Each time, everytime the file /proc/helloworld is read, the function + procfs_read is called. + Two parameters of this function are very important: the buffer (the first parameter) and the offset (the third one). + The content of the buffer will be returned to the application which read it (for example the cat command). The offset + is the current position in the file. If the return value of the function isn't null, then this function is + called again. So be careful with this function, if it never returns zero, the read function is called endlessly. + + + +% cat /proc/helloworld +HelloWorld! + - -procfs.c + +procfs1.c + + + + +Read and Write a /proc File + + + We have seen a very simple example for a /proc file where we only read the file /proc/helloworld. + It's also possible to write in a /proc file. It works the same way as read, a function is called when the /proc + file is written. But there is a little difference with read, data comes from user, so you have to import data from + user space to kernel space (with copy_from_user or get_user) + + + get_user + put_user + copy_from_user + copy_to_user + memory segments + segmentmemory + + + The reason for copy_from_user or get_user is that Linux memory (on Intel + architecture, it may be different under some other processors) is segmented. This means that a pointer, by itself, + does not reference a unique location in memory, only a location in a memory segment, and you need to know which + memory segment it is to be able to use it. There is one memory segment for the kernel, and one for each of the processes. + + + + The only memory segment accessible to a process is its own, so when writing regular programs to run as processes, + there's no need to worry about segments. When you write a kernel module, normally you want to access the kernel memory + segment, which is handled automatically by the system. However, when the content of a memory buffer needs to be passed between + the currently running process and the kernel, the kernel function receives a pointer to the memory buffer which is in the + process segment. The put_user and get_user macros allow you to access that + memory. These functions handle only one caracter, you can handle several caracters with copy_to_user and + copy_from_user. As the buffer (in read or write function) is in kernel space, for write function + you need to import data because it comes from user space, but not for the read function because data is already + in kernel space. + + + readin the kernel + writein the kernel + + +procfs2.c + + + + + + + + +Manage /proc file with standard filesystem + + + We have seen how to read and write a /proc file with the /proc interface. But it's also possible + to manage /proc file with inodes. The main interest is to use advanced function, like permissions. + + + + In Linux, there is a standard mechanism for file system registration. Since every file system has to have its own + functions to handle inode and file operationsThe difference between the two is that file operations deal with + the file itself, and inode operations deal with ways of referencing the file, such as creating links to it., + there is a special structure to hold pointers to all those functions, struct inode_operations, which + includes a pointer to struct file_operations. In /proc, whenever we register a new file, we're allowed to + specify which struct inode_operations will be used to access to it. This is the mechanism we use, a + struct inode_operations which includes a pointer to a struct file_operations which + includes pointers to our procfs_read and procfs_write functions. + + + filesystemregistration + filesystem registration + struct inode_operations + inode_operations structure + struct file_operations + file_operations structure + + + Another interesting point here is the module_permission function. This function is called whenever + a process tries to do something with the /proc file, and it can decide whether to allow + access or not. Right now it is only based on the operation and the uid of the current user (as available in + current, a pointer to a structure which includes information on the currently running process), but it + could be based on anything we like, such as what other processes are doing with the same file, the time of day, or the last + input we received. + + pointercurrent + permission + module_permissions + + + It's important to note that the standard roles of read and write are reversed in the kernel. Read functions are used for + output, whereas write functions are used for input. The reason for that is that read and write refer to the user's point of + view --- if a process reads something from the kernel, then the kernel needs to output it, and if a process writes something + to the kernel, then the kernel receives it as input. + + + +procfs3.c + + + + + + + Still hungry for procfs examples? Well, first of all keep in mind, there are rumors around, claiming + that procfs is on it's way out, consider using sysfs instead. Second, if you really can't get enough, + there's a highly recommendable bonus level for procfs below linux/Documentation/DocBook/ . + Use make help in your toplevel kernel directory for instructions about how to convert it into + your favourite format. Example: make htmldocs . Consider using this mechanism, + in case you want to document something kernel related yourself. + + + + diff --git a/LDP/guide/docbook/lkmpg/2.6/10-ReplacingPrintks.sgml b/LDP/guide/docbook/lkmpg/2.6/10-ReplacingPrintks.sgml index 46dac52a..4aa4a9d3 100644 --- a/LDP/guide/docbook/lkmpg/2.6/10-ReplacingPrintks.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/10-ReplacingPrintks.sgml @@ -29,10 +29,10 @@ Flashing keyboard LEDs keyboard LEDsflashing - In certain conditions, you may desire for your module a simpler and more direct way to communicate to the external world that he's running. + In certain conditions, you may desire a simpler and more direct way to communicate to the external world. Flashing keyboard LEDs can be such a solution: It is an immediate way to attract attention or to display a status condition. Keyboard LEDs are present on every hardware, they are always visible, they do not need any setup, and their use is rather simple and - non-intrusive, if compared to writing to a tty or a file. + non-intrusive, compared to writing to a tty or a file. The following source code illustrates a minimal kernel module which, when loaded, starts blinking the keyboard LEDs until it is unloaded. @@ -45,14 +45,14 @@ The following source code illustrates a minimal kernel module which, when loaded CONFIG_LL_DEBUG in make menuconfig is good for? If you activate that you get low level access to the serial port. While this might not sound very powerful by itself, you can patch kernel/printk.c or any other essential syscall to use printascii, thus makeing it possible to trace virtually everything what your code does over a - serial line. If your architecture does not support this and is equipped with a serial port, this might be one of the - first things that should be implemented. Logging over a netconsole might also be worth a try. + serial line. If you find yourself porting the kernel to some new and former unsupported architecture this is usually + amongst the first things that should be implemented. Logging over a netconsole might also be worth a try. While you have seen lots of stuff that can be used to aid debugging here, there are some things to be aware of. Debugging is almost always intrusive. Adding debug code can change the situation enough to make the bug seem to dissappear. - Thus you should try to keep debug code to a minimum and make shure it does not show up in production code. + Thus you should try to keep debug code to a minimum and make sure it does not show up in production code. diff --git a/LDP/guide/docbook/lkmpg/2.6/11-SchedulingTasks.sgml b/LDP/guide/docbook/lkmpg/2.6/11-SchedulingTasks.sgml index ba23c33f..02bc9cd5 100644 --- a/LDP/guide/docbook/lkmpg/2.6/11-SchedulingTasks.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/11-SchedulingTasks.sgml @@ -13,15 +13,14 @@ kernel module which is in memory anyway. task - tq_struct - queue_task - tq_timer + workqueue_struct + queue_delayed_work Instead of doing that, we can create a function that will be called once for every timer interrupt. The way we do this - is we create a task, held in a tq_struct structure, which will hold a pointer to the function. Then, - we use queue_task to put that task on a task list called tq_timer, which is the - list of tasks to be executed on the next timer interrupt. Because we want the function to keep on being executed, we need to - put it back on tq_timer whenever it is called, for the next timer interrupt. + is we create a task, held in a workqueue_struct structure, which will hold a pointer to the function. Then, + we use queue_delayed_work to put that task on a task list called my_workqueue, + which is the list of tasks to be executed on the next timer interrupt. Because we want the function to keep on being executed, + we need to put it back on my_workqueue whenever it is called, for the next timer interrupt. rmmod reference count @@ -29,22 +28,8 @@ There's one more point we need to remember here. When a module is removed by rmmod, first its reference count is checked. If it is zero, module_cleanup is called. Then, the module is removed from - memory with all its functions. Nobody checks to see if the timer's task list happens to contain a pointer to one of those - functions, which will no longer be available. Ages later (from the computer's perspective, from a human perspective it's - nothing, less than a hundredth of a second), the kernel has a timer interrupt and tries to call the function on the task list. - Unfortunately, the function is no longer there. In most cases, the memory page where it sat is unused, and you get an ugly - error message. But if some other code is now sitting at the same memory location, things could get very - ugly. Unfortunately, we don't have an easy way to unregister a task from a task list. - - sleep_on - module_sleep_on - - Since cleanup_module can't return with an error code (it's a void function), the solution is to not - let it return at all. Instead, it calls sleep_on or - module_sleep_onThey're really the same. to put the - rmmod process to sleep. Before that, it informs the function called on the timer interrupt to stop - attaching itself by setting a global variable. Then, on the next timer interrupt, the rmmod process will - be woken up, when our function is no longer in the queue and it's safe to remove the module. + memory with all its functions. Things need to be shut down properly, or bad things will happen. See the code below how + this can be done in a safe way. source filesched.c diff --git a/LDP/guide/docbook/lkmpg/2.6/12-InterruptHandlers.sgml b/LDP/guide/docbook/lkmpg/2.6/12-InterruptHandlers.sgml index 152c284a..55a836bf 100644 --- a/LDP/guide/docbook/lkmpg/2.6/12-InterruptHandlers.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/12-InterruptHandlers.sgml @@ -42,32 +42,35 @@ SA_INTERRUPT SA_SHIRQ - The way to implement this is to call request_irq() to get your interrupt handler called when - the relevant IRQ is received (there are 15 of them, plus 1 which is used to cascade the interrupt controllers, on Intel - platforms). This function receives the IRQ number, the name of the function, flags, a name for - /proc/interrupts and a parameter to pass to the interrupt handler. The flags can include - SA_SHIRQ to indicate you're willing to share the IRQ with other interrupt handlers (usually because - a number of hardware devices sit on the same IRQ) and SA_INTERRUPT to indicate this is a fast - interrupt. This function will only succeed if there isn't already a handler on this IRQ, or if you're both willing to - share. + The way to implement this is to call request_irq() to get your interrupt handler called + when the relevant IRQ is received. - queue_task_irq - tq_immediate - mark_bh - BH_IMMEDIATE + + In practice IRQ handling can be a bit more complex. Hardware is often designed in a way that chains two interrupt + controllers, so that all the IRQs from interrupt controller B are cascaded to a certain IRQ from + interrupt controller A. Of course that requires that the kernel finds out which IRQ it really was + afterwards and that adds overhead. Other architectures offer some special, very low overhead, + so called "fast IRQ" or FIQs. To take advantage of them requires handlers to be written in assembler, + so they do not really fit into the kernel. They can be made to work similar to the others, but after + that procedure, they're no longer any faster than "common" IRQs. SMP enabled kernels running on systems + with more than one processor need to solve another truckload of problems. It's not enough to know if a certain IRQs + has happend, it's also important for what CPU(s) it was for. People still interested in more details, + might want to do a web search for "APIC" now ;) + + + This function receives the IRQ number, the name of the function, flags, a name for + /proc/interrupts and a parameter to pass to the interrupt handler. + Usually there is a certain number of IRQs available. How many IRQs there are is hardware dependant. + The flags can include SA_SHIRQ to indicate you're willing to share the IRQ with other + interrupt handlers (usually because a number of hardware devices sit on the same IRQ) and + SA_INTERRUPT to indicate this is a fast interrupt. This function will only succeed if + there isn't already a handler on this IRQ, or if you're both willing to share. + + queue_work Then, from within the interrupt handler, we communicate with the hardware and then use - queue_task_irq() with tq_immediate() and - mark_bh(BH_IMMEDIATE) to schedule the bottom half. The reason we can't use the standard - queue_task queue_task in version 2.0 is that the interrupt - might happen right in the middle of somebody else's - queue_taskqueue_task_irq is protected from this by a global lock - -- in 2.2 there is no queue_task_irq and queue_task is protected by a - lock.. We need mark_bh because earlier versions of Linux only had an array of 32 - bottom halves, and now one of them (BH_IMMEDIATE) is used for the linked list of bottom halves for - drivers which didn't get a bottom half entry assigned to them. - - + queue_work() mark_bh(BH_IMMEDIATE) to schedule the bottom half. + diff --git a/LDP/guide/docbook/lkmpg/2.6/A1-ChangesBet20And22.sgml b/LDP/guide/docbook/lkmpg/2.6/A1-ChangesBet20And22.sgml index 350e322c..a6541dd1 100644 --- a/LDP/guide/docbook/lkmpg/2.6/A1-ChangesBet20And22.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/A1-ChangesBet20And22.sgml @@ -1,91 +1,20 @@ -Changes between 2.0 and 2.2 +Changes between 2.4 and 2.6 - 2.2 changes + 2.6 changes kernelversions + Changes between 2.4 and 2.6 - - Changes between 2.0 and 2.2 - - I don't know the entire kernel well enough do document all of the changes. In the course of converting the examples - (or actually, adapting Emmanuel Papirakis's changes) I came across the following differences. I listed all of them here - together to help module programmers, especially those who learned from previous versions of this book and are most - familiar with the techniques I use, convert to the new version. - - An additional resource for people who wish to convert to 2.2 is located on Richard Gooch's site . - - asm/uaccess.h - asmuaccess.h - put_user - get_user - structurefile_operations - flush - close - read - write - ssize_t - proc_register_dynamic - signals - queue_task_irq - queue_task - interrupts - irqs - moduleparameters - module parameters - MODULE_PARM - Symmetrical Multi-Processing - SMP - - - - asm/uaccess.h - If you need put_user or get_user you have to - #include it. - - get_user - In version 2.2, get_user receives both the pointer into user memory and the - variable in kernel memory to fill with the information. The reason for this is that get_user can - now read two or four bytes at a time if the variable we read is two or four bytes long. - - file_operations - This structure now has a flush function between the open and - close functions. - - close in file_operations - In version 2.2, the close function returns an integer, so it's allowed to - fail. - - read,write in file_operations - The headers for these functions changed. They now return ssize_t instead of an - integer, and their parameter list is different. The inode is no longer a parameter, and on the other hand the offset - into the file is. - - proc_register_dynamic - This function no longer exists. Instead, you call the regular proc_register - proc_register and put zero in the inode field of the - structure. - - Signals - The signals in the task structure are no longer a 32 bit integer, but an array of - _NSIG_WORDS _NSIG_WORDS - integers. - - queue_task_irq - Even if you want to scheduale a task to happen from inside an interrupt handler, you use - queue_task, not queue_task_irq. - - Module Parameters - You no longer just declare module parameters as global variables. In 2.2 you have to also use - MODULE_PARM to declare their type. This is a big improvement, because it allows the module to - receive string parameters which start with a digits, for example, without getting - confused. - - Symmetrical Multi-Processing - The kernel is no longer inside one huge spinlock, which means that kernel modules have to be aware of - SMP. - - + I don't know the entire kernel well enough to document all of the changes. + Some hints for porting can be found by comparing this version of the LKMPG with it's counterpart for + kernel 2.4. Apart from that, anybody who needs to port drivers from 2.4 to 2.6 kernels might want to visit + http://lwn.net/Articles/driver-porting/ . + If you still can't find an example that exactly meets your needs there, find a driver that's similar to your driver + and present in both kernel versions. File comparison tools like xxdiff or + meld can be a great help then. Also check if your driver is covered by docs in + linux/Documentation/ . Before starting with porting and in case you're stuck it's + a good idea to find an appropiate mailinglist and ask people there for pointers. + diff --git a/LDP/guide/docbook/lkmpg/2.6/A2-WhereToGoFromHere.sgml b/LDP/guide/docbook/lkmpg/2.6/A2-WhereToGoFromHere.sgml index dbff1ae5..0df1948f 100644 --- a/LDP/guide/docbook/lkmpg/2.6/A2-WhereToGoFromHere.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/A2-WhereToGoFromHere.sgml @@ -17,6 +17,9 @@ I hope I have helped you in your quest to become a better programmer, or at least to have fun through technology. And, if you do write useful kernel modules, I hope you publish them under the GPL, so I can use them too. + If you'd like to contribute to this guide, please contact one the maintainers for details. As you've + already seen, there's a placeholder chapter now, waiting to be filled with examples for sysfs. + diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile index 5c2a25d6..f31fb3c4 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile @@ -5,3 +5,9 @@ obj-m += hello-4.o obj-m += hello-5.o obj-m += startstop.o startstop-objs := start.o stop.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.1 b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.1 index 0c61cc28..fbd8a058 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.1 +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.1 @@ -1,2 +1,7 @@ obj-m += hello-1.o +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.2 b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.2 index e46317c9..bde2c762 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.2 +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/Makefile.2 @@ -1,2 +1,8 @@ obj-m += hello-1.o obj-m += hello-2.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-1.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-1.c index f322d9ec..a9fef793 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-1.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-1.c @@ -2,11 +2,11 @@ * hello-1.c - The simplest kernel module. */ #include /* Needed by all modules */ -#include /* Needed for KERN_ALERT */ +#include /* Needed for KERN_INFO */ int init_module(void) { - printk("<1>Hello world 1.\n"); + printk(KERN_INFO "Hello world 1.\n"); /* * A non 0 return means init_module failed; module can't be loaded. @@ -16,5 +16,5 @@ int init_module(void) void cleanup_module(void) { - printk(KERN_ALERT "Goodbye world 1.\n"); + printk(KERN_INFO "Goodbye world 1.\n"); } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-2.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-2.c index e05292a5..445ec21c 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-2.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-2.c @@ -3,18 +3,18 @@ * This is preferred over using init_module() and cleanup_module(). */ #include /* Needed by all modules */ -#include /* Needed for KERN_ALERT */ +#include /* Needed for KERN_INFO */ #include /* Needed for the macros */ static int __init hello_2_init(void) { - printk(KERN_ALERT "Hello, world 2\n"); + printk(KERN_INFO "Hello, world 2\n"); return 0; } static void __exit hello_2_exit(void) { - printk(KERN_ALERT "Goodbye, world 2\n"); + printk(KERN_INFO "Goodbye, world 2\n"); } module_init(hello_2_init); diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-3.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-3.c index 51a85908..a4eaf269 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-3.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-3.c @@ -2,20 +2,20 @@ * hello-3.c - Illustrating the __init, __initdata and __exit macros. */ #include /* Needed by all modules */ -#include /* Needed for KERN_ALERT */ +#include /* Needed for KERN_INFO */ #include /* Needed for the macros */ static int hello3_data __initdata = 3; static int __init hello_3_init(void) { - printk(KERN_ALERT "Hello, world %d\n", hello3_data); + printk(KERN_INFO "Hello, world %d\n", hello3_data); return 0; } static void __exit hello_3_exit(void) { - printk(KERN_ALERT "Goodbye, world 3\n"); + printk(KERN_INFO "Goodbye, world 3\n"); } module_init(hello_3_init); diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-4.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-4.c index 70b51a41..398230d4 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-4.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-4.c @@ -1,21 +1,21 @@ /* * hello-4.c - Demonstrates module documentation. */ -#include -#include -#include +#include /* Needed by all modules */ +#include /* Needed for KERN_INFO */ +#include /* Needed for the macros */ #define DRIVER_AUTHOR "Peter Jay Salzman " #define DRIVER_DESC "A sample driver" static int __init init_hello_4(void) { - printk(KERN_ALERT "Hello, world 4\n"); + printk(KERN_INFO "Hello, world 4\n"); return 0; } static void __exit cleanup_hello_4(void) { - printk(KERN_ALERT "Goodbye, world 4\n"); + printk(KERN_INFO "Goodbye, world 4\n"); } module_init(init_hello_4); diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-5.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-5.c index 75fd500a..77b9d112 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-5.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/hello-5.c @@ -14,6 +14,8 @@ static short int myshort = 1; static int myint = 420; static long int mylong = 9999; static char *mystring = "blah"; +static int myintArray[2] = { -1, -1 }; +static int arr_argc = 0; /* * module_param(foo, int, 0000) @@ -32,19 +34,36 @@ MODULE_PARM_DESC(mylong, "A long integer"); module_param(mystring, charp, 0000); MODULE_PARM_DESC(mystring, "A character string"); +/* + * module_param_array(name, type, num, perm); + * The first param is the parameter's (in this case the array's) name + * The second param is the data type of the elements of the array + * The third argument is a pointer to the variable that will store the number + * of elements of the array initialized by the user at module loading time + * The fourth argument is the permission bits + */ +module_param_array(myintArray, int, &arr_argc, 0000); +MODULE_PARM_DESC(myintArray, "An array of integers"); + static int __init hello_5_init(void) { - printk(KERN_ALERT "Hello, world 5\n=============\n"); - printk(KERN_ALERT "myshort is a short integer: %hd\n", myshort); - printk(KERN_ALERT "myint is an integer: %d\n", myint); - printk(KERN_ALERT "mylong is a long integer: %ld\n", mylong); - printk(KERN_ALERT "mystring is a string: %s\n", mystring); + int i; + printk(KERN_INFO "Hello, world 5\n=============\n"); + printk(KERN_INFO "myshort is a short integer: %hd\n", myshort); + printk(KERN_INFO "myint is an integer: %d\n", myint); + printk(KERN_INFO "mylong is a long integer: %ld\n", mylong); + printk(KERN_INFO "mystring is a string: %s\n", mystring); + for (i = 0; i < (sizeof myintArray / sizeof (int)); i++) + { + printk(KERN_INFO "myintArray[%d] = %d\n", i, myintArray[i]); + } + printk(KERN_INFO "got %d arguments for myintArray.\n", arr_argc); return 0; } static void __exit hello_5_exit(void) { - printk(KERN_ALERT "Goodbye, world 5\n"); + printk(KERN_INFO "Goodbye, world 5\n"); } module_init(hello_5_init); diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/start.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/start.c index 74e1b17a..369035fa 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/start.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/start.c @@ -7,6 +7,6 @@ int init_module(void) { - printk("Hello, world - this is the kernel speaking\n"); + printk(KERN_INFO "Hello, world - this is the kernel speaking\n"); return 0; } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/stop.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/stop.c index 66024e56..3331f5f1 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/stop.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/02-HelloWorld/stop.c @@ -7,5 +7,5 @@ void cleanup_module() { - printk("<1>Short is the life of a kernel module\n"); + printk(KERN_INFO "Short is the life of a kernel module\n"); } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/Makefile index 93df0bf5..878fabd2 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/Makefile @@ -1 +1,12 @@ +# +# This is a sort a recursive Makefile +# This Makefile is used to compile the module +# + obj-m += chardev.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/chardev.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/chardev.c index 19de4688..3b76eba1 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/chardev.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/04-CharacterDeviceFiles/chardev.c @@ -40,29 +40,30 @@ static struct file_operations fops = { }; /* - * Functions + * This function is called when the module is loaded */ - int init_module(void) { - Major = register_chrdev(0, DEVICE_NAME, &fops); + Major = register_chrdev(0, DEVICE_NAME, &fops); if (Major < 0) { - printk("Registering the character device failed with %d\n", - Major); - return Major; + printk(KERN_ALERT "Registering char device failed with %d\n", Major); + return Major; } - printk("<1>I was assigned major number %d. To talk to\n", Major); - printk("<1>the driver, create a dev file with\n"); - printk("'mknod /dev/hello c %d 0'.\n", Major); - printk("<1>Try various minor numbers. Try to cat and echo to\n"); - printk("the device file.\n"); - printk("<1>Remove the device file and module when done.\n"); + printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major); + printk(KERN_INFO "the driver, create a dev file with\n"); + printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major); + printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n"); + printk(KERN_INFO "the device file.\n"); + printk(KERN_INFO "Remove the device file and module when done.\n"); - return 0; + return SUCCESS; } +/* + * This function is called when the module is unloaded + */ void cleanup_module(void) { /* @@ -70,7 +71,7 @@ void cleanup_module(void) */ int ret = unregister_chrdev(Major, DEVICE_NAME); if (ret < 0) - printk("Error in unregister_chrdev: %d\n", ret); + printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret); } /* @@ -84,8 +85,10 @@ void cleanup_module(void) static int device_open(struct inode *inode, struct file *file) { static int counter = 0; + if (Device_Open) return -EBUSY; + Device_Open++; sprintf(msg, "I already told you %d times Hello world!\n", counter++); msg_Ptr = msg; @@ -160,6 +163,6 @@ static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off) { - printk("<1>Sorry, this operation isn't supported.\n"); + printk(KERN_ALERT "Sorry, this operation isn't supported.\n"); return -EINVAL; } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/Makefile index cf519b72..2998bec2 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/05-TheProcFileSystem/Makefile @@ -1 +1,7 @@ -obj-m += procfs.o +obj-m += procfs1.o procfs2.o procfs3.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/Makefile index cf519b72..f5dbf526 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/Makefile @@ -1 +1,7 @@ obj-m += procfs.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/procfs.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/procfs.c index 2651ce77..c42de5fa 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/procfs.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/06-UsingProcForInput/procfs.c @@ -165,10 +165,12 @@ int init_module() Our_Proc_File->gid = 0; Our_Proc_File->size = 80; + printk(KERN_INFO "/proc/rw_test created\n"); return 0; /* success */ } void cleanup_module() { remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root); + printk(KERN_INFO "/proc/rw_test removed\n"); } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/Makefile index 93df0bf5..c73f3b95 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/Makefile @@ -1 +1,13 @@ obj-m += chardev.o + +all: ioctl module + +module: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +install: + mknod /proc/char_dev c 100 0 + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + rm -f ioctl diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/chardev.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/chardev.c index cc5c6b5d..3e916d91 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/chardev.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/07-TalkingToDeviceFiles/chardev.c @@ -36,7 +36,7 @@ static char *Message_Ptr; static int device_open(struct inode *inode, struct file *file) { #ifdef DEBUG - printk("device_open(%p)\n", file); + printk(KERN_INFO "device_open(%p)\n", file); #endif /* @@ -57,7 +57,7 @@ static int device_open(struct inode *inode, struct file *file) static int device_release(struct inode *inode, struct file *file) { #ifdef DEBUG - printk("device_release(%p,%p)\n", inode, file); + printk(KERN_INFO "device_release(%p,%p)\n", inode, file); #endif /* @@ -85,7 +85,7 @@ static ssize_t device_read(struct file *file, /* see include/linux/fs.h */ int bytes_read = 0; #ifdef DEBUG - printk("device_read(%p,%p,%d)\n", file, buffer, length); + printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length); #endif /* @@ -113,7 +113,7 @@ static ssize_t device_read(struct file *file, /* see include/linux/fs.h */ } #ifdef DEBUG - printk("Read %d bytes, %d left\n", bytes_read, length); + printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length); #endif /* @@ -134,7 +134,7 @@ device_write(struct file *file, int i; #ifdef DEBUG - printk("device_write(%p,%s,%d)", file, buffer, length); + printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length); #endif for (i = 0; i < length && i < BUF_LEN; i++) @@ -247,20 +247,20 @@ int init_module() * Negative values signify an error */ if (ret_val < 0) { - printk("%s failed with %d\n", + printk(KERN_ALERT "%s failed with %d\n", "Sorry, registering the character device ", ret_val); return ret_val; } - printk("%s The major device number is %d.\n", + printk(KERN_INFO "%s The major device number is %d.\n", "Registeration is a success", MAJOR_NUM); - printk("If you want to talk to the device driver,\n"); - printk("you'll have to create a device file. \n"); - printk("We suggest you use:\n"); - printk("mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM); - printk("The device file name is important, because\n"); - printk("the ioctl program assumes that's the\n"); - printk("file you'll use.\n"); + printk(KERN_INFO "If you want to talk to the device driver,\n"); + printk(KERN_INFO "you'll have to create a device file. \n"); + printk(KERN_INFO "We suggest you use:\n"); + printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM); + printk(KERN_INFO "The device file name is important, because\n"); + printk(KERN_INFO "the ioctl program assumes that's the\n"); + printk(KERN_INFO "file you'll use.\n"); return 0; } @@ -281,5 +281,5 @@ void cleanup_module() * If there's an error, report it */ if (ret < 0) - printk("Error in module_unregister_chrdev: %d\n", ret); + printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret); } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/Makefile index 82b11a8e..332678d1 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/Makefile @@ -1 +1,7 @@ obj-m += syscall.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/syscall.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/syscall.c index 40dda213..b88247ff 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/syscall.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/08-SystemCalls/syscall.c @@ -112,13 +112,13 @@ int init_module() * Warning - too late for it now, but maybe for * next time... */ - printk("I'm dangerous. I hope you did a "); - printk("sync before you insmod'ed me.\n"); - printk("My counterpart, cleanup_module(), is even"); - printk("more dangerous. If\n"); - printk("you value your file system, it will "); - printk("be \"sync; rmmod\" \n"); - printk("when you remove this module.\n"); + printk(KERN_ALERT "I'm dangerous. I hope you did a "); + printk(KERN_ALERT "sync before you insmod'ed me.\n"); + printk(KERN_ALERT "My counterpart, cleanup_module(), is even"); + printk(KERN_ALERT "more dangerous. If\n"); + printk(KERN_ALERT "you value your file system, it will "); + printk(KERN_ALERT "be \"sync; rmmod\" \n"); + printk(KERN_ALERT "when you remove this module.\n"); /* * Keep a pointer to the original function in @@ -133,7 +133,7 @@ int init_module() * call foo, go to sys_call_table[__NR_foo]. */ - printk("Spying on UID:%d\n", uid); + printk(KERN_INFO "Spying on UID:%d\n", uid); return 0; } @@ -147,10 +147,10 @@ void cleanup_module() * Return the system call back to normal */ if (sys_call_table[__NR_open] != our_sys_open) { - printk("Somebody else also played with the "); - printk("open system call\n"); - printk("The system may be left in "); - printk("an unstable state.\n"); + printk(KERN_ALERT "Somebody else also played with the "); + printk(KERN_ALERT "open system call\n"); + printk(KERN_ALERT "The system may be left in "); + printk(KERN_ALERT "an unstable state.\n"); } sys_call_table[__NR_open] = original_call; diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/Makefile index 75332846..d5656d94 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/Makefile @@ -1 +1,10 @@ obj-m += sleep.o + +all: cat_noblock module + +module: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + rm -f cat_noblock diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/sleep.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/sleep.c index 0397fb4a..9bd4593f 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/sleep.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/09-BlockingProcesses/sleep.c @@ -276,8 +276,15 @@ static struct inode_operations Inode_Ops_4_Our_Proc_File = { int init_module() { - int rv = 0; + Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL); + + if (Our_Proc_File == NULL) { + remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root); + printk(KERN_ALERT "Error: Could not initialize /proc/test\n"); + return -ENOMEM; + } + Our_Proc_File->owner = THIS_MODULE; Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File; Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File; @@ -285,14 +292,10 @@ int init_module() Our_Proc_File->uid = 0; Our_Proc_File->gid = 0; Our_Proc_File->size = 80; - - if (Our_Proc_File == NULL) { - rv = -ENOMEM; - remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root); - printk(KERN_INFO "Error: Could not initialize /proc/test\n"); - } - - return rv; + + printk(KERN_INFO "/proc/test created\n"); + + return 0; } /* @@ -304,4 +307,6 @@ int init_module() void cleanup_module() { remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root); + + printk(KERN_INFO "/proc/test removed\n"); } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/10-ReplacingPrintks/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/10-ReplacingPrintks/Makefile index 80d46413..156b4534 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/10-ReplacingPrintks/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/10-ReplacingPrintks/Makefile @@ -1,2 +1,8 @@ obj-m += print_string.o obj-m += kbleds.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/Makefile index 37d9220c..8d9d31a8 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/Makefile @@ -1 +1,7 @@ obj-m += sched.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/sched.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/sched.c index 5e04f228..19c1dbd8 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/sched.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/11-SchedulingTasks/sched.c @@ -76,10 +76,8 @@ procfile_read(char *buffer, */ static char my_buffer[80]; - static int count = 1; - /* - * We give all of our information in one go, so if the anybody asks us + * We give all of our information in one go, so if anybody asks us * if we have more information the answer should always be no. */ if (offset > 0) @@ -89,7 +87,6 @@ procfile_read(char *buffer, * Fill the buffer and get its length */ len = sprintf(my_buffer, "Timer called %d times so far\n", TimerIntrpt); - count++; /* * Tell the function which called us where the buffer is @@ -107,23 +104,18 @@ procfile_read(char *buffer, */ int __init init_module() { - int rv = 0; - /* - * Put the task in the work_timer task queue, so it will be executed at - * next timer interrupt + /* + * Create our /proc file */ - my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME); - queue_delayed_work(my_workqueue, &Task, 100); - Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL); + if (Our_Proc_File == NULL) { - rv = -ENOMEM; remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root); - printk(KERN_INFO "Error: Could not initialize /proc/%s\n", + printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROC_ENTRY_FILENAME); + return -ENOMEM; } - - + Our_Proc_File->read_proc = procfile_read; Our_Proc_File->owner = THIS_MODULE; Our_Proc_File->mode = S_IFREG | S_IRUGO; @@ -131,7 +123,17 @@ int __init init_module() Our_Proc_File->gid = 0; Our_Proc_File->size = 80; - return rv; + /* + * Put the task in the work_timer task queue, so it will be executed at + * next timer interrupt + */ + my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME); + queue_delayed_work(my_workqueue, &Task, 100); + + + printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME); + + return 0; } /* diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/Makefile b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/Makefile index a8ff9a3c..56ff30d1 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/Makefile +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/Makefile @@ -1 +1,7 @@ obj-m += intrpt.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/intrpt.c b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/intrpt.c index 98b40d2d..428c5265 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/intrpt.c +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg-examples/12-InterruptHandlers/intrpt.c @@ -28,7 +28,7 @@ static struct workqueue_struct *my_workqueue; */ static void got_char(void *scancode) { - printk("Scan Code %x %s.\n", + printk(KERN_INFO "Scan Code %x %s.\n", (int)*((char *)scancode) & 0x7F, *((char *)scancode) & 0x80 ? "Released" : "Pressed"); } diff --git a/LDP/guide/docbook/lkmpg/2.6/lkmpg.sgml b/LDP/guide/docbook/lkmpg/2.6/lkmpg.sgml index 00729309..5c76b834 100644 --- a/LDP/guide/docbook/lkmpg/2.6/lkmpg.sgml +++ b/LDP/guide/docbook/lkmpg/2.6/lkmpg.sgml @@ -29,7 +29,7 @@ - 2005-01-23 ver 2.6.1 + 2005-05-26 ver 2.6.1 @@ -38,33 +38,29 @@ - The Linux Kernel Module Programming Guide is a free book; you may reproduce and/or - modify it under the terms of the Open Software License, version 1.1. You can obtain a copy of - this license at The Linux Kernel Module Programming Guide is a free book; you may reproduce and/or modify it under the terms of the + Open Software License, version 1.1. You can obtain a copy of this license at http://opensource.org/licenses/osl.php. - This book is distributed in the hope it will be useful, but without any warranty, - without even the implied warranty of merchantability or fitness for a particular - purpose. + This book is distributed in the hope it will be useful, but without any warranty, without even the implied warranty + of merchantability or fitness for a particular purpose. - The author encourages wide distribution of this book for personal or commercial use, - provided the above copyright notice remains intact and the method adheres to the provisions of - the Open Software License. In summary, you may copy and distribute this book free of charge - or for a profit. No explicit permission is required from the author for reproduction of this - book in any medium, physical or electronic. + The author encourages wide distribution of this book for personal or commercial use, provided the above copyright + notice remains intact and the method adheres to the provisions of the Open Software License. In summary, you may copy and + distribute this book free of charge or for a profit. No explicit permission is required from the author for reproduction + of this book in any medium, physical or electronic. - Derivative works and translations of this document must be placed under the Open - Software License, and the original copyright notice must remain intact. If you have - contributed new material to this book, you must make the material and source code available - for your revisions. Please make revisions and updates available directly to the document - maintainer, Peter Jay Salzman p@dirac.org. This will allow for the merging of - updates and provide consistent revisions to the Linux community. + Derivative works and translations of this document must be placed under the Open Software License, and the original + copyright notice must remain intact. If you have contributed new material to this book, you must make the material and + source code available for your revisions. Please make revisions and updates available directly to the document + maintainer, Peter Jay Salzman p@dirac.org. This will allow for the merging of updates and provide + consistent revisions to the Linux community. - If you publish or distribute this book commercially, donations, royalties, and/or - printed copies are greatly appreciated by the author and the Linux Documentation Project (LDP). Contributing in this way - shows your support for free software and the LDP. If you have questions or comments, please - contact the address above. + If you publish or distribute this book commercially, donations, royalties, and/or printed copies are greatly + appreciated by the author and the Linux Documentation Project (LDP). + Contributing in this way shows your support for free software and the LDP. If you have questions or comments, please + contact the address above. + @@ -91,5 +87,5 @@