├── .cproject
├── .gitignore
├── .project
├── LICENSE
├── Makefile
├── README.Debian
├── README.md
├── include
├── access_ok_version.h
├── lddbus.h
└── proc_ops_version.h
├── init
├── lddbus
├── Makefile
└── lddbus.c
├── misc-modules
├── Makefile
├── complete.c
├── faulty.c
├── hello.c
├── hellop.c
├── jiq.c
├── jit.c
├── kdataalign.c
├── kdatasize.c
├── module_load
├── module_unload
├── seq.c
├── silly.c
└── sleepy.c
├── misc-progs
├── Makefile
├── asynctest.c
├── dataalign.c
├── datasize.c
├── gdbline
├── inp.c
├── load50.c
├── mapcmp.c
├── mapper.c
├── nbtest.c
├── netifdebug.c
├── outp.c
├── polltest.c
├── setconsole.c
├── setlevel.c
└── test
│ ├── .gitignore
│ └── nonblock.sh
├── pci
├── Makefile
└── pci_skel.c
├── sbull
├── Makefile
├── sbull.c
├── sbull.h
├── sbull_load
└── sbull_unload
├── scull-shared
├── scull-async.c
└── scull-async.h
├── scull
├── Makefile
├── access.c
├── main.c
├── pipe.c
├── scull.h
├── scull.init
├── scull_load
└── scull_unload
├── scullc
├── Makefile
├── main.c
├── mmap.c
├── scull-shared
│ ├── scull-async.c
│ └── scull-async.h
├── scullc.h
├── scullc_load
└── scullc_unload
├── sculld
├── Makefile
├── main.c
├── mmap.c
├── scull-shared
│ ├── scull-async.c
│ └── scull-async.h
├── sculld.h
├── sculld_load
└── sculld_unload
├── scullp
├── Makefile
├── main.c
├── mmap.c
├── scull-shared
│ ├── scull-async.c
│ └── scull-async.h
├── scullp.h
├── scullp_load
└── scullp_unload
├── scullv
├── Makefile
├── main.c
├── mmap.c
├── scull-shared
│ ├── scull-async.c
│ └── scull-async.h
├── scullv.h
├── scullv_load
└── scullv_unload
├── short
├── Makefile
├── short.c
├── short_load
└── short_unload
├── shortprint
├── Makefile
├── shortprint.c
├── shortprint.h
├── shortprint_load
└── shortprint_unload
├── simple
├── Makefile
├── simple.c
├── simple_load
└── simple_unload
├── skull
├── Makefile
├── skull_clean.c
└── skull_init.c
├── snull
├── Makefile
├── snull.c
├── snull.h
├── snull_load
└── snull_unload
├── tty
├── Makefile
├── tiny_serial.c
└── tiny_tty.c
└── usb
├── Makefile
└── usb-skeleton.c
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
77 |
78 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # vim
2 | *.sw[a-z]
3 | *.un~
4 | Session.vim
5 |
6 | # make file
7 | .*
8 | !.gitignore
9 | *~
10 | *.o
11 | core
12 | *.ko
13 | *.mod.c
14 | Module.symvers
15 | modules.order
16 | *.mod
17 | *.a
18 |
19 | # misc-progs
20 | nbtest
21 | load50
22 | mapcmp
23 | polltest
24 | mapper
25 | setlevel
26 | setconsole
27 | inp
28 | outp
29 | datasize
30 | dataalign
31 | netifdebug
32 | asynctest
33 |
34 | # Allows for Eclipse CDT lookups without checking in linux source
35 | linux_source_cdt
36 | !.project
37 | !.cproject
38 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ldd3
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 |
14 |
15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
16 | full,incremental,
17 |
18 |
19 |
20 |
21 |
22 | org.eclipse.cdt.core.cnature
23 | org.eclipse.cdt.core.ccnature
24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
26 |
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 |
3 | Unless otherwise stated, the source code distributed with this book
4 | can be redistributed in source or binary form so long as an
5 | acknowledgment appears in derived source files. The citation should
6 | list that the code comes from BOOK by AUTHOR, published by O'Reilly &
7 | Associates. This code is under copyright and cannot be included in
8 | any other book, publication, or educational product without permission
9 | from O'Reilly & Associates. No warranty is attached; we cannot take
10 | responsibility for errors or fitness for use.
11 |
12 |
13 | There are a few exception to this licence, however: a few sources
14 | herein are distributed according to the GNU General Public License,
15 | version 2. You'll find a copy of the license in
16 | /usr/src/linux/COPYING, and in other places in your filesystem. The
17 | affected source files are:
18 |
19 | pci/pci_skel.c
20 | tty/tiny_serial.c
21 | tty/tiny_tty.c
22 | usb/usb-skeleton.c
23 |
24 | The files in ./pci ./tty and ./usb inherit the GPL from the kernel
25 | sources, as most of their code comes straight from the kernel
26 | (usb-skeleton.c being part of the kernel source tree directly.)
27 |
28 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | SUBDIRS = misc-progs misc-modules \
3 | skull scull scullc scullp lddbus sculld scullv shortprint simple tty \
4 | pci usb\
5 | sbull snull short
6 |
7 | all: subdirs
8 |
9 | subdirs:
10 | for n in $(SUBDIRS); do $(MAKE) -C $$n || exit 1; done
11 |
12 | clean:
13 | for n in $(SUBDIRS); do $(MAKE) -C $$n clean; done
14 |
--------------------------------------------------------------------------------
/README.Debian:
--------------------------------------------------------------------------------
1 | Compiling in Debian
2 | -------------------
3 |
4 | In order to build examples for current prebuilt kernel, you should install
5 | linux-headers package for you current kernel:
6 |
7 | $ sudo apt-get install linux-headers-$(uname -r)
8 |
9 | You will also need make tools:
10 |
11 | $ sudo apt-get install make
12 |
13 | Now just run make in example dir you want to build.
14 |
15 | NOTE: These examples were designed for latest linux kernel and you might not
16 | be able to build some of them for older prebuilt kernels from Debian-based
17 | distributives.
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ldd3: Linux Device Drivers 3 examples updated to work with recent kernels
2 |
3 | # About
4 | -----
5 |
6 | Linux Device Drivers 3 (http://lwn.net/Kernel/LDD3/) book is now a few years
7 | old and most of the example drivers do not compile in recent kernels.
8 |
9 | This project aims to keep LDD3 example drivers up-to-date with recent kernels.
10 |
11 | The original code can be found at: http://examples.oreilly.com/9780596005900/
12 |
13 | # Compiling
14 | ----------
15 |
16 | The example drivers should compile against latest Linus Torvalds kernel tree:
17 | * git://git.kernel.org/pub/scm/linux/kernel/git/sfr/linux-next.git
18 |
19 | To compile the drivers against a specific tree (for example Linus tree):
20 | ```
21 | $ git clone git://github.com/martinezjavier/ldd3.git
22 | $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
23 | $ export KERNELDIR=/path/to/linux
24 | $ cd ldd3
25 | $ make
26 | ```
27 |
28 | Bugs, comments or patches: See https://github.com/martinezjavier/ldd3/issues
29 |
30 | # Latest Tested Kernel Builds
31 | ---------
32 | The kernel builds below are the versions most recently tested/supported
33 |
34 | * Ubuntu 18.04 kernel as of July 2020: 5.4.0-42-generic
35 | * Ubuntu 20.04 kernel as of July 2021: 5.4.0-73-generic
36 | * Yocto poky warrior branch kernel for qemu aarch64 builds: 5.0.19
37 | * Yocto poky hardknott branch kernel for qemu aarch64 builds: 5.10.46
38 | * Buildroot 2019.05 kernel for qemu builds: 4.9.16
39 | * Buildroot 2021.02 kernel for qemu builds: 5.10
40 | * Alpine 3.13 kernel as of May 2021: 5.10.29-lts, see [here](https://github.com/ericwq/gccIDE/wiki/ldd3-project) for detail.
41 |
42 |
43 | # Eclipse Integration
44 | ---------4
45 | Eclipse CDT integration is provided by symlinking the correct linux source directory with the ./linux_source_cdt symlink.
46 | The .project and .cproject files were setup using instructions in [this link](https://wiki.eclipse.org/HowTo_use_the_CDT_to_navigate_Linux_kernel_source)
47 | and assuming a symlink is setup in the local project directory to point to relevant kernel headers
48 |
49 | This can be done on a system with kernel headers installed using:
50 | ```
51 | ln -s /usr/src/linux-headers-`uname -r`/ linux_source_cdt
52 | ```
53 |
--------------------------------------------------------------------------------
/include/access_ok_version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * @file access_ok_version.h
3 | * @date 10/13/2019
4 | *
5 | */
6 |
7 | #include
8 |
9 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
10 | #define access_ok_wrapper(type,arg,cmd) \
11 | access_ok(type, arg, cmd)
12 | #else
13 | #define access_ok_wrapper(type,arg,cmd) \
14 | access_ok(arg, cmd)
15 | #endif
16 |
--------------------------------------------------------------------------------
/include/lddbus.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Definitions for the virtual LDD bus.
3 | *
4 | * $Id: lddbus.h,v 1.4 2004/08/20 18:49:44 corbet Exp $
5 | */
6 |
7 | //extern struct device ldd_bus;
8 | extern struct bus_type ldd_bus_type;
9 |
10 |
11 | /*
12 | * The LDD driver type.
13 | */
14 |
15 | struct ldd_driver {
16 | char *version;
17 | struct module *module;
18 | struct device_driver driver;
19 | struct driver_attribute version_attr;
20 | };
21 |
22 | #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);
23 |
24 | /*
25 | * A device type for things "plugged" into the LDD bus.
26 | */
27 |
28 | struct ldd_device {
29 | char *name;
30 | struct ldd_driver *driver;
31 | struct device dev;
32 | };
33 |
34 | #define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);
35 |
36 | extern int register_ldd_device(struct ldd_device *);
37 | extern void unregister_ldd_device(struct ldd_device *);
38 | extern int register_ldd_driver(struct ldd_driver *);
39 | extern void unregister_ldd_driver(struct ldd_driver *);
40 |
--------------------------------------------------------------------------------
/include/proc_ops_version.h:
--------------------------------------------------------------------------------
1 | #ifndef _PROC_OPS_VERSION_H
2 | #define _PROC_OPS_VERSION_H
3 |
4 | #include
5 |
6 | #ifdef CONFIG_COMPAT
7 | #define __add_proc_ops_compat_ioctl(pops, fops) \
8 | (pops)->proc_compat_ioctl = (fops)->compat_ioctl
9 | #else
10 | #define __add_proc_ops_compat_ioctl(pops, fops)
11 | #endif
12 |
13 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
14 | #define proc_ops_wrapper(fops, newname) (fops)
15 | #else
16 | #define proc_ops_wrapper(fops, newname) \
17 | ({ \
18 | static struct proc_ops newname; \
19 | \
20 | newname.proc_open = (fops)->open; \
21 | newname.proc_read = (fops)->read; \
22 | newname.proc_write = (fops)->write; \
23 | newname.proc_release = (fops)->release; \
24 | newname.proc_poll = (fops)->poll; \
25 | newname.proc_ioctl = (fops)->unlocked_ioctl; \
26 | newname.proc_mmap = (fops)->mmap; \
27 | newname.proc_get_unmapped_area = (fops)->get_unmapped_area; \
28 | newname.proc_lseek = (fops)->llseek; \
29 | __add_proc_ops_compat_ioctl(&newname, fops); \
30 | &newname; \
31 | })
32 | #endif
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/init:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 |
4 | case "$1" in
5 | start)
6 | echo "Starting init script for Module Loading"
7 | start-stop-daemon -S -n init -a /bin/scull_load
8 | start-stop-daemon -S -n init -a /bin/module_load -- hello
9 | ;;
10 | stop)
11 | echo "Removing user modules"
12 | start-stop-daemon -K -n scull_load
13 | start-stop-daemon -K -n module_load
14 | start-stop-daemon -S -n init -a /bin/scull_unload
15 | start-stop-daemon -S -n init -a /bin/module_unload -- hello
16 | ;;
17 | *)
18 | echo "Usage: $0 {start|stop}"
19 | exit 1
20 | esac
21 | exit 0
22 |
--------------------------------------------------------------------------------
/lddbus/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 | # Add your debugging flag (or not) to CFLAGS
5 | ifeq ($(DEBUG),y)
6 | DEBFLAGS = -O -g # "-O" is needed to expand inlines
7 | else
8 | DEBFLAGS = -O2
9 | endif
10 |
11 | LDDINCDIR=$(PWD)/../include
12 | EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR)
13 |
14 | ifneq ($(KERNELRELEASE),)
15 | # call from kernel build system
16 |
17 | obj-m := lddbus.o
18 |
19 | else
20 |
21 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
22 | PWD := $(shell pwd)
23 |
24 | default:
25 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
26 |
27 | endif
28 |
29 |
30 |
31 | clean:
32 | rm -rf *.o *.ko *~ core .depend *.mod.c .*.cmd .tmp_versions .*.o.d *.mod modules.order *.symvers
33 |
34 | depend .depend dep:
35 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
36 |
37 |
38 | ifeq (.depend,$(wildcard .depend))
39 | include .depend
40 | endif
41 |
--------------------------------------------------------------------------------
/lddbus/lddbus.c:
--------------------------------------------------------------------------------
1 | /*
2 | * A virtual bus for LDD sample code devices to plug into. This
3 | * code is heavily borrowed from drivers/base/sys.c
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | *
16 | */
17 | /* $Id: lddbus.c,v 1.9 2004/09/26 08:12:27 gregkh Exp $ */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include "lddbus.h"
26 |
27 | MODULE_AUTHOR("Jonathan Corbet");
28 | MODULE_LICENSE("Dual BSD/GPL");
29 | static char *Version = "$Revision: 1.9 $";
30 |
31 | /*
32 | * Respond to udev events.
33 | */
34 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0))
35 | static int ldd_uevent(struct device *dev, struct kobj_uevent_env *env)
36 | #else
37 | static int ldd_uevent(const struct device *dev, struct kobj_uevent_env *env)
38 | #endif
39 | {
40 | if (add_uevent_var(env, "LDDBUS_VERSION=%s", Version))
41 | return -ENOMEM;
42 |
43 | return 0;
44 | }
45 |
46 | /*
47 | * Match LDD devices to drivers. Just do a simple name test.
48 | */
49 | static int ldd_match(struct device *dev, struct device_driver *driver)
50 | {
51 | return !strncmp(dev_name(dev), driver->name, strlen(driver->name));
52 | }
53 |
54 |
55 | /*
56 | * The LDD bus device.
57 | */
58 | static void ldd_bus_release(struct device *dev)
59 | {
60 | printk(KERN_DEBUG "lddbus release\n");
61 | }
62 |
63 | struct device ldd_bus = {
64 | .release = ldd_bus_release
65 | };
66 |
67 |
68 | /*
69 | * And the bus type.
70 | */
71 | struct bus_type ldd_bus_type = {
72 | .name = "ldd",
73 | .match = ldd_match,
74 | .uevent = ldd_uevent,
75 | };
76 |
77 | /*
78 | * Export a simple attribute.
79 | */
80 | /* Changed in kernel commit 75cff725d9566699a670a02b3cfd1c6e9e9ed53e
81 | * driver core: bus: mark the struct bus_type for sysfs callbacks as constant */
82 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0))
83 | static ssize_t version_show(struct bus_type *bus, char *buf)
84 | #else
85 | static ssize_t version_show(const struct bus_type *bus, char *buf)
86 | #endif
87 | {
88 | return snprintf(buf, PAGE_SIZE, "%s\n", Version);
89 | }
90 |
91 | static BUS_ATTR_RO(version);
92 |
93 |
94 |
95 | /*
96 | * LDD devices.
97 | */
98 |
99 | /*
100 | * For now, no references to LDDbus devices go out which are not
101 | * tracked via the module reference count, so we use a no-op
102 | * release function.
103 | */
104 | static void ldd_dev_release(struct device *dev)
105 | { }
106 |
107 | int register_ldd_device(struct ldd_device *ldddev)
108 | {
109 | ldddev->dev.bus = &ldd_bus_type;
110 | ldddev->dev.parent = &ldd_bus;
111 | ldddev->dev.release = ldd_dev_release;
112 | dev_set_name(&ldddev->dev, ldddev->name);
113 | return device_register(&ldddev->dev);
114 | }
115 | EXPORT_SYMBOL(register_ldd_device);
116 |
117 | void unregister_ldd_device(struct ldd_device *ldddev)
118 | {
119 | device_unregister(&ldddev->dev);
120 | }
121 | EXPORT_SYMBOL(unregister_ldd_device);
122 |
123 | /*
124 | * Crude driver interface.
125 | */
126 |
127 |
128 | static ssize_t show_version(struct device_driver *driver, char *buf)
129 | {
130 | struct ldd_driver *ldriver = to_ldd_driver(driver);
131 |
132 | sprintf(buf, "%s\n", ldriver->version);
133 | return strlen(buf);
134 | }
135 |
136 |
137 | int register_ldd_driver(struct ldd_driver *driver)
138 | {
139 | int ret;
140 |
141 | driver->driver.bus = &ldd_bus_type;
142 | ret = driver_register(&driver->driver);
143 | if (ret)
144 | return ret;
145 | driver->version_attr.attr.name = "version";
146 | driver->version_attr.attr.mode = S_IRUGO;
147 | driver->version_attr.show = show_version;
148 | driver->version_attr.store = NULL;
149 | return driver_create_file(&driver->driver, &driver->version_attr);
150 | }
151 |
152 | void unregister_ldd_driver(struct ldd_driver *driver)
153 | {
154 | driver_unregister(&driver->driver);
155 | }
156 | EXPORT_SYMBOL(register_ldd_driver);
157 | EXPORT_SYMBOL(unregister_ldd_driver);
158 |
159 |
160 |
161 | static int __init ldd_bus_init(void)
162 | {
163 | int ret;
164 |
165 | ret = bus_register(&ldd_bus_type);
166 | if (ret) {
167 | printk(KERN_ERR "Unable to register ldd bus, failure was %d\n",ret);
168 | return ret;
169 | }
170 | if (bus_create_file(&ldd_bus_type, &bus_attr_version))
171 | printk(KERN_ERR "Unable to create version attribute\n");
172 | dev_set_name(&ldd_bus,"ldd0");
173 | ret = device_register(&ldd_bus);
174 | if (ret) {
175 | printk(KERN_ERR "Unable to register ldd0, failure was %d\n",ret);
176 | goto out_fail;
177 | }
178 | return 0;
179 |
180 | out_fail:
181 | bus_unregister(&ldd_bus_type);
182 | return ret;
183 | }
184 |
185 | static void ldd_bus_exit(void)
186 | {
187 | device_unregister(&ldd_bus);
188 | bus_unregister(&ldd_bus_type);
189 | }
190 |
191 | module_init(ldd_bus_init);
192 | module_exit(ldd_bus_exit);
193 |
--------------------------------------------------------------------------------
/misc-modules/Makefile:
--------------------------------------------------------------------------------
1 |
2 | # To build modules outside of the kernel tree, we run "make"
3 | # in the kernel source tree; the Makefile these then includes this
4 | # Makefile once again.
5 | # This conditional selects whether we are being included from the
6 | # kernel Makefile or not.
7 |
8 | LDDINC=$(PWD)/../include
9 | EXTRA_CFLAGS += -I$(LDDINC)
10 |
11 | ifeq ($(KERNELRELEASE),)
12 |
13 | # Assume the source tree is where the running kernel was built
14 | # You should set KERNELDIR in the environment if it's elsewhere
15 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
16 | # The current directory is passed to sub-makes as argument
17 | PWD := $(shell pwd)
18 |
19 | modules:
20 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
21 |
22 | modules_install:
23 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
24 |
25 | clean:
26 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
27 |
28 | .PHONY: modules modules_install clean
29 |
30 | else
31 | # called from kernel build system: just declare what our modules are
32 | obj-m := hello.o hellop.o seq.o jiq.o sleepy.o complete.o \
33 | silly.o faulty.o kdatasize.o kdataalign.o jit.o
34 | endif
35 |
36 |
37 |
--------------------------------------------------------------------------------
/misc-modules/complete.c:
--------------------------------------------------------------------------------
1 | /*
2 | * complete.c -- the writers awake the readers
3 | *
4 | * Copyright (C) 2003 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2003 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: complete.c,v 1.2 2004/09/26 07:02:43 gregkh Exp $
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include /* current and everything */
22 | #include /* printk() */
23 | #include /* everything... */
24 | #include /* size_t */
25 | #include
26 |
27 | MODULE_LICENSE("Dual BSD/GPL");
28 |
29 | static int complete_major = 0;
30 |
31 | DECLARE_COMPLETION(comp);
32 |
33 | ssize_t complete_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
34 | {
35 | printk(KERN_DEBUG "process %i (%s) going to sleep\n",
36 | current->pid, current->comm);
37 | wait_for_completion(&comp);
38 | printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
39 | return 0; /* EOF */
40 | }
41 |
42 | ssize_t complete_write (struct file *filp, const char __user *buf, size_t count,
43 | loff_t *pos)
44 | {
45 | printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
46 | current->pid, current->comm);
47 | complete(&comp);
48 | return count; /* succeed, to avoid retrial */
49 | }
50 |
51 |
52 | struct file_operations complete_fops = {
53 | .owner = THIS_MODULE,
54 | .read = complete_read,
55 | .write = complete_write,
56 | };
57 |
58 |
59 | int complete_init(void)
60 | {
61 | int result;
62 |
63 | /*
64 | * Register your major, and accept a dynamic number
65 | */
66 | result = register_chrdev(complete_major, "complete", &complete_fops);
67 | if (result < 0)
68 | return result;
69 | if (complete_major == 0)
70 | complete_major = result; /* dynamic */
71 | return 0;
72 | }
73 |
74 | void complete_cleanup(void)
75 | {
76 | unregister_chrdev(complete_major, "complete");
77 | }
78 |
79 | module_init(complete_init);
80 | module_exit(complete_cleanup);
81 |
82 |
--------------------------------------------------------------------------------
/misc-modules/faulty.c:
--------------------------------------------------------------------------------
1 | /*
2 | * faulty.c -- a module which generates an oops when read
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: faulty.c,v 1.3 2004/09/26 07:02:43 gregkh Exp $
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include /* printk() */
22 | #include /* everything... */
23 | #include /* size_t */
24 | #include
25 |
26 | MODULE_LICENSE("Dual BSD/GPL");
27 |
28 |
29 | int faulty_major = 0;
30 |
31 | ssize_t faulty_read(struct file *filp, char __user *buf,
32 | size_t count, loff_t *pos)
33 | {
34 | int i;
35 | int ret;
36 | char stack_buf[4];
37 |
38 | /* Let's try a buffer overflow */
39 | for (i = 0; i < 20; i++)
40 | *(stack_buf + i) = 0xff;
41 | if (count > 4)
42 | count = 4; /* copy 4 bytes to the user */
43 | ret = copy_to_user(buf, stack_buf, count);
44 | if (!ret)
45 | return count;
46 | return ret;
47 | }
48 |
49 | ssize_t faulty_write (struct file *filp, const char __user *buf, size_t count,
50 | loff_t *pos)
51 | {
52 | /* make a simple fault by dereferencing a NULL pointer */
53 | *(int *)0 = 0;
54 | return 0;
55 | }
56 |
57 |
58 |
59 | struct file_operations faulty_fops = {
60 | .read = faulty_read,
61 | .write = faulty_write,
62 | .owner = THIS_MODULE
63 | };
64 |
65 |
66 | int faulty_init(void)
67 | {
68 | int result;
69 |
70 | /*
71 | * Register your major, and accept a dynamic number
72 | */
73 | result = register_chrdev(faulty_major, "faulty", &faulty_fops);
74 | if (result < 0)
75 | return result;
76 | if (faulty_major == 0)
77 | faulty_major = result; /* dynamic */
78 |
79 | return 0;
80 | }
81 |
82 | void faulty_cleanup(void)
83 | {
84 | unregister_chrdev(faulty_major, "faulty");
85 | }
86 |
87 | module_init(faulty_init);
88 | module_exit(faulty_cleanup);
89 |
90 |
--------------------------------------------------------------------------------
/misc-modules/hello.c:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id: hello.c,v 1.5 2004/10/26 03:32:21 corbet Exp $
3 | */
4 | #include
5 | #include
6 | MODULE_LICENSE("Dual BSD/GPL");
7 |
8 | static int hello_init(void)
9 | {
10 | printk(KERN_ALERT "Hello, world\n");
11 | return 0;
12 | }
13 |
14 | static void hello_exit(void)
15 | {
16 | printk(KERN_ALERT "Goodbye, cruel world\n");
17 | }
18 |
19 | module_init(hello_init);
20 | module_exit(hello_exit);
21 |
--------------------------------------------------------------------------------
/misc-modules/hellop.c:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id: hellop.c,v 1.4 2004/09/26 07:02:43 gregkh Exp $
3 | */
4 | #include
5 | #include
6 | #include
7 |
8 | MODULE_LICENSE("Dual BSD/GPL");
9 |
10 | /*
11 | * These lines, although not shown in the book,
12 | * are needed to make hello.c run properly even when
13 | * your kernel has version support enabled
14 | */
15 |
16 |
17 | /*
18 | * A couple of parameters that can be passed in: how many times we say
19 | * hello, and to whom.
20 | */
21 | static char *whom = "world";
22 | static int howmany = 1;
23 | module_param(howmany, int, S_IRUGO);
24 | module_param(whom, charp, S_IRUGO);
25 |
26 | static int hello_init(void)
27 | {
28 | int i;
29 | for (i = 0; i < howmany; i++)
30 | printk(KERN_ALERT "(%d) Hello, %s\n", i, whom);
31 | return 0;
32 | }
33 |
34 | static void hello_exit(void)
35 | {
36 | printk(KERN_ALERT "Goodbye, cruel world\n");
37 | }
38 |
39 | module_init(hello_init);
40 | module_exit(hello_exit);
41 |
--------------------------------------------------------------------------------
/misc-modules/jiq.c:
--------------------------------------------------------------------------------
1 | /*
2 | * jiq.c -- the just-in-queue module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * jiq.c,v 1.7 2004/09/26 07:02:43 gregkh Exp
16 | */
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #include
23 | #include
24 | #include /* everything... */
25 | #include
26 | #include
27 | #include /* error codes */
28 | #include
29 | #include
30 | #include /* tasklets */
31 |
32 | #include "proc_ops_version.h"
33 | MODULE_LICENSE("Dual BSD/GPL");
34 |
35 | /*
36 | * The delay for the delayed workqueue timer file.
37 | */
38 | static long delay = 1;
39 | module_param(delay, long, 0);
40 |
41 | /*
42 | * This module is a silly one: it only embeds short code fragments
43 | * that show how enqueued tasks `feel' the environment
44 | */
45 |
46 | #define LIMIT (PAGE_SIZE-128) /* don't print any more after this size */
47 |
48 | /*
49 | * Print information about the current environment. This is called from
50 | * within the task queues. If the limit is reched, awake the reading
51 | * process.
52 | */
53 | static DECLARE_WAIT_QUEUE_HEAD(jiq_wait);
54 |
55 | /*
56 | * Keep track of info we need between task queue runs.
57 | */
58 | static struct clientdata {
59 | struct work_struct jiq_work;
60 | struct delayed_work jiq_delayed_work;
61 | struct timer_list jiq_timer;
62 | struct tasklet_struct jiq_tasklet;
63 | struct seq_file *m;
64 | int len;
65 | unsigned long jiffies;
66 | long delay;
67 | } jiq_data;
68 |
69 | #define SCHEDULER_QUEUE ((task_queue *) 1)
70 |
71 | static void jiq_print_tasklet(unsigned long);
72 |
73 | /*
74 | * Do the printing; return non-zero if the task should be rescheduled.
75 | */
76 | static int jiq_print(struct clientdata *data)
77 | {
78 | int len = data->len;
79 | struct seq_file *m = data->m;
80 | unsigned long j = jiffies;
81 |
82 | if (len > LIMIT) {
83 | wake_up_interruptible(&jiq_wait);
84 | return 0;
85 | }
86 |
87 | if (len == 0) {
88 | seq_puts(m, " time delta preempt pid cpu command\n");
89 | len = m->count;
90 | } else {
91 | len = 0;
92 | }
93 |
94 | /* intr_count is only exported since 1.3.5,
95 | but 1.99.4 is needed anyways */
96 | seq_printf(m, "%9li %4li %3i %5i %3i %s\n",
97 | j, j - data->jiffies,
98 | preempt_count(), current->pid, smp_processor_id(),
99 | current->comm);
100 | len += m->count;
101 |
102 | data->len += len;
103 | data->jiffies = j;
104 | return 1;
105 | }
106 |
107 |
108 | /*
109 | * Call jiq_print from a work queue
110 | */
111 | static void jiq_print_wq(struct work_struct *work)
112 | {
113 | struct clientdata *data = container_of(work,
114 | struct clientdata, jiq_work);
115 |
116 | if (!jiq_print(data))
117 | return;
118 |
119 | schedule_work(&jiq_data.jiq_work);
120 | }
121 |
122 | static void jiq_print_wq_delayed(struct work_struct *work)
123 | {
124 | struct clientdata *data = container_of(work, struct clientdata,
125 | jiq_delayed_work.work);
126 |
127 | if (!jiq_print (data))
128 | return;
129 |
130 | schedule_delayed_work(&jiq_data.jiq_delayed_work, data->delay);
131 | }
132 |
133 |
134 | static int jiq_read_wq_show(struct seq_file *m, void *v)
135 | {
136 | DEFINE_WAIT(wait);
137 |
138 | jiq_data.len = 0; /* nothing printed, yet */
139 | jiq_data.m = m; /* print in this place */
140 | jiq_data.jiffies = jiffies; /* initial time */
141 | jiq_data.delay = 0;
142 |
143 | prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
144 | schedule_work(&jiq_data.jiq_work);
145 | schedule();
146 | finish_wait(&jiq_wait, &wait);
147 |
148 | return 0;
149 | }
150 |
151 | static int jiq_read_wq_open(struct inode *inode, struct file *file)
152 | {
153 | return single_open(file, jiq_read_wq_show, NULL);
154 | }
155 |
156 | static const struct file_operations jiq_read_wq_fops = {
157 | .open = jiq_read_wq_open,
158 | .read = seq_read,
159 | .llseek = seq_lseek,
160 | .release = single_release,
161 | };
162 |
163 | static int jiq_read_wq_delayed_show(struct seq_file *m, void *v)
164 | {
165 | DEFINE_WAIT(wait);
166 |
167 | jiq_data.len = 0; /* nothing printed, yet */
168 | jiq_data.m = m; /* print in this place */
169 | jiq_data.jiffies = jiffies; /* initial time */
170 | jiq_data.delay = delay;
171 |
172 | prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
173 | schedule_delayed_work(&jiq_data.jiq_delayed_work, delay);
174 | schedule();
175 | finish_wait(&jiq_wait, &wait);
176 |
177 | return 0;
178 | }
179 |
180 | static int jiq_read_wq_delayed_open(struct inode *inode, struct file *file)
181 | {
182 | return single_open(file, jiq_read_wq_delayed_show, NULL);
183 | }
184 |
185 | static const struct file_operations jiq_read_wq_delayed_fops = {
186 | .open = jiq_read_wq_delayed_open,
187 | .read = seq_read,
188 | .llseek = seq_lseek,
189 | .release = single_release,
190 | };
191 |
192 | /*
193 | * Call jiq_print from a tasklet
194 | */
195 | static void jiq_print_tasklet(unsigned long ptr)
196 | {
197 | struct clientdata *data = (struct clientdata *)ptr;
198 | if (jiq_print(data))
199 | tasklet_schedule(&data->jiq_tasklet);
200 | }
201 |
202 | static int jiq_read_tasklet_show(struct seq_file *m, void *v)
203 | {
204 | jiq_data.len = 0; /* nothing printed, yet */
205 | jiq_data.m = m; /* print in this place */
206 | jiq_data.jiffies = jiffies; /* initial time */
207 |
208 | tasklet_schedule(&jiq_data.jiq_tasklet);
209 | wait_event_interruptible(jiq_wait, 0); /* sleep till completion */
210 |
211 | return 0;
212 | }
213 |
214 | static int jiq_read_tasklet_open(struct inode *inode, struct file *file)
215 | {
216 | return single_open(file, jiq_read_tasklet_show, NULL);
217 | }
218 |
219 | static const struct file_operations jiq_read_tasklet_fops = {
220 | .open = jiq_read_tasklet_open,
221 | .read = seq_read,
222 | .llseek = seq_lseek,
223 | .release = single_release,
224 | };
225 |
226 | /*
227 | * This one, instead, tests out the timers.
228 | */
229 |
230 | static void jiq_timedout(struct timer_list *t)
231 | {
232 | struct clientdata *data = from_timer(data, t, jiq_timer);
233 | jiq_print(data); /* print a line */
234 | wake_up_interruptible(&jiq_wait); /* awake the process */
235 | }
236 |
237 | static int jiq_read_run_timer_show(struct seq_file *m, void *v)
238 | {
239 | jiq_data.len = 0; /* prepare the argument for jiq_print() */
240 | jiq_data.m = m;
241 | jiq_data.jiffies = jiffies;
242 |
243 | timer_setup(&jiq_data.jiq_timer, jiq_timedout, 0);
244 | jiq_data.jiq_timer.expires = jiffies + HZ; /* one second */
245 |
246 | jiq_print(&jiq_data); /* print and go to sleep */
247 | add_timer(&jiq_data.jiq_timer);
248 | wait_event_interruptible(jiq_wait, 0); /* RACE */
249 | del_timer_sync(&jiq_data.jiq_timer); /* in case a signal woke us up */
250 |
251 | return 0;
252 | }
253 |
254 | static int jiq_read_run_timer_open(struct inode *inode, struct file *file)
255 | {
256 | return single_open(file, jiq_read_run_timer_show, NULL);
257 | }
258 |
259 | static const struct file_operations jiq_read_run_timer_fops = {
260 | .open = jiq_read_run_timer_open,
261 | .read = seq_read,
262 | .llseek = seq_lseek,
263 | .release = single_release,
264 | };
265 |
266 | /*
267 | * the init/clean material
268 | */
269 |
270 | static int jiq_init(void)
271 | {
272 | /* this line is in jiq_init() */
273 | INIT_WORK(&jiq_data.jiq_work, jiq_print_wq);
274 | INIT_DELAYED_WORK(&jiq_data.jiq_delayed_work, jiq_print_wq_delayed);
275 | tasklet_init(&jiq_data.jiq_tasklet, jiq_print_tasklet,
276 | (unsigned long)&jiq_data);
277 |
278 | proc_create("jiqwq", 0, NULL,
279 | proc_ops_wrapper(&jiq_read_wq_fops, jiq_read_wq_pops));
280 | proc_create("jiqwqdelay", 0, NULL,
281 | proc_ops_wrapper(&jiq_read_wq_delayed_fops, jiq_read_wq_delayed_pops));
282 | proc_create("jitimer", 0, NULL,
283 | proc_ops_wrapper(&jiq_read_run_timer_fops, jiq_read_run_timer_pops));
284 | proc_create("jiqtasklet", 0, NULL,
285 | proc_ops_wrapper(&jiq_read_tasklet_fops, jiq_read_tasklet_pops));
286 |
287 | return 0; /* succeed */
288 | }
289 |
290 | static void jiq_cleanup(void)
291 | {
292 | remove_proc_entry("jiqwq", NULL);
293 | remove_proc_entry("jiqwqdelay", NULL);
294 | remove_proc_entry("jitimer", NULL);
295 | remove_proc_entry("jiqtasklet", NULL);
296 | }
297 |
298 |
299 | module_init(jiq_init);
300 | module_exit(jiq_cleanup);
301 |
--------------------------------------------------------------------------------
/misc-modules/jit.c:
--------------------------------------------------------------------------------
1 | /*
2 | * jit.c -- the just-in-time module
3 | *
4 | * Copyright (C) 2001,2003 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001,2003 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * jit.c,v 1.16 2004/09/26 07:02:43 gregkh Exp
16 | */
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include "proc_ops_version.h"
37 | /*
38 | * This module is a silly one: it only embeds short code fragments
39 | * that show how time delays can be handled in the kernel.
40 | */
41 |
42 | int delay = HZ; /* the default delay, expressed in jiffies */
43 |
44 | module_param(delay, int, 0);
45 |
46 | MODULE_AUTHOR("Alessandro Rubini");
47 | MODULE_LICENSE("Dual BSD/GPL");
48 |
49 | /* use these as data pointers, to implement four files in one function */
50 | enum jit_files {
51 | JIT_BUSY,
52 | JIT_SCHED,
53 | JIT_QUEUE,
54 | JIT_SCHEDTO
55 | };
56 |
57 | /*
58 | * This function prints one line of data, after sleeping one second.
59 | * It can sleep in different ways, according to the data pointer
60 | */
61 | int jit_fn_show(struct seq_file *m, void *v)
62 | {
63 | unsigned long j0, j1; /* jiffies */
64 | wait_queue_head_t wait;
65 | long data = (long)m->private;
66 |
67 | init_waitqueue_head(&wait);
68 | j0 = jiffies;
69 | j1 = j0 + delay;
70 |
71 | switch (data) {
72 | case JIT_BUSY:
73 | while (time_before(jiffies, j1))
74 | cpu_relax();
75 | break;
76 | case JIT_SCHED:
77 | while (time_before(jiffies, j1))
78 | schedule();
79 | break;
80 | case JIT_QUEUE:
81 | wait_event_interruptible_timeout(wait, 0, delay);
82 | break;
83 | case JIT_SCHEDTO:
84 | set_current_state(TASK_INTERRUPTIBLE);
85 | schedule_timeout(delay);
86 | break;
87 | }
88 | j1 = jiffies; /* actual value after we delayed */
89 |
90 | seq_printf(m, "%9li %9li\n", j0, j1);
91 | return 0;
92 | }
93 |
94 | static int jit_fn_open(struct inode *inode, struct file *file)
95 | {
96 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)
97 | return single_open(file, jit_fn_show, PDE_DATA(inode));
98 | #else
99 | return single_open(file, jit_fn_show, pde_data(inode));
100 | #endif
101 | }
102 |
103 | static const struct file_operations jit_fn_fops = {
104 | .open = jit_fn_open,
105 | .read = seq_read,
106 | .llseek = seq_lseek,
107 | .release = single_release,
108 | };
109 |
110 | /*
111 | * This file, on the other hand, returns the current time forever
112 | */
113 | int jit_currentime_show(struct seq_file *m, void *v)
114 | {
115 | unsigned long j1;
116 | u64 j2;
117 |
118 | /* get them four */
119 | j1 = jiffies;
120 | j2 = get_jiffies_64();
121 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
122 | {
123 | struct timeval tv1;
124 | struct timespec tv2;
125 | do_gettimeofday(&tv1);
126 | tv2 = current_kernel_time();
127 | /* print */
128 | seq_printf(m, "0x%08lx 0x%016Lx %10i.%06i\n"
129 | "%40i.%09i\n",
130 | j1, j2,
131 | (int) tv1.tv_sec, (int) tv1.tv_usec,
132 | (int) tv2.tv_sec, (int) tv2.tv_nsec);
133 | }
134 | #else
135 | {
136 | struct timespec64 tv1;
137 | struct timespec64 tv2;
138 | ktime_get_real_ts64(&tv1);
139 | ktime_get_coarse_real_ts64(&tv2);
140 | seq_printf(m, "0x%08lx 0x%016Lx %10i.%09i\n"
141 | "%40i.%09i\n",
142 | j1, j2,
143 | (int) tv1.tv_sec, (int) tv1.tv_nsec,
144 | (int) tv2.tv_sec, (int) tv2.tv_nsec);
145 |
146 | }
147 | #endif
148 |
149 | return 0;
150 | }
151 |
152 | static int jit_currentime_open(struct inode *inode, struct file *file)
153 | {
154 | return single_open(file, jit_currentime_show, NULL);
155 | }
156 |
157 | static const struct file_operations jit_currentime_fops = {
158 | .open = jit_currentime_open,
159 | .read = seq_read,
160 | .llseek = seq_lseek,
161 | .release = single_release,
162 | };
163 |
164 | /*
165 | * The timer example follows
166 | */
167 |
168 | int tdelay = 10;
169 | module_param(tdelay, int, 0);
170 |
171 | /* This data structure used as "data" for the timer and tasklet functions */
172 | struct jit_data {
173 | struct timer_list timer;
174 | struct tasklet_struct tlet;
175 | struct seq_file *m;
176 | int hi; /* tasklet or tasklet_hi */
177 | wait_queue_head_t wait;
178 | unsigned long prevjiffies;
179 | int loops;
180 | };
181 | #define JIT_ASYNC_LOOPS 5
182 |
183 | void jit_timer_fn(struct timer_list *t)
184 | {
185 | struct jit_data *data = from_timer(data, t, timer);
186 | unsigned long j = jiffies;
187 | seq_printf(data->m, "%9li %3li %i %6i %i %s\n",
188 | j, j - data->prevjiffies, in_interrupt() ? 1 : 0,
189 | current->pid, smp_processor_id(), current->comm);
190 |
191 | if (--data->loops) {
192 | data->timer.expires += tdelay;
193 | data->prevjiffies = j;
194 | add_timer(&data->timer);
195 | } else {
196 | wake_up_interruptible(&data->wait);
197 | }
198 | }
199 |
200 | /* the /proc function: allocate everything to allow concurrency */
201 | int jit_timer_show(struct seq_file *m, void *v)
202 | {
203 | struct jit_data *data;
204 | unsigned long j = jiffies;
205 |
206 | data = kmalloc(sizeof(*data), GFP_KERNEL);
207 | if (!data)
208 | return -ENOMEM;
209 |
210 | init_waitqueue_head(&data->wait);
211 |
212 | /* write the first lines in the buffer */
213 | seq_puts(m, " time delta inirq pid cpu command\n");
214 | seq_printf(m, "%9li %3li %i %6i %i %s\n",
215 | j, 0L, in_interrupt() ? 1 : 0,
216 | current->pid, smp_processor_id(), current->comm);
217 |
218 | /* fill the data for our timer function */
219 | data->prevjiffies = j;
220 | data->m = m;
221 | data->loops = JIT_ASYNC_LOOPS;
222 |
223 | /* register the timer */
224 | timer_setup(&data->timer, jit_timer_fn, 0);
225 | data->timer.expires = j + tdelay; /* parameter */
226 | add_timer(&data->timer);
227 |
228 | /* wait for the buffer to fill */
229 | wait_event_interruptible(data->wait, !data->loops);
230 | if (signal_pending(current))
231 | return -ERESTARTSYS;
232 | kfree(data);
233 | return 0;
234 | }
235 |
236 | static int jit_timer_open(struct inode *inode, struct file *file)
237 | {
238 | return single_open(file, jit_timer_show, NULL);
239 | }
240 |
241 | static const struct file_operations jit_timer_fops = {
242 | .open = jit_timer_open,
243 | .read = seq_read,
244 | .llseek = seq_lseek,
245 | .release = single_release,
246 | };
247 |
248 | void jit_tasklet_fn(unsigned long arg)
249 | {
250 | struct jit_data *data = (struct jit_data *)arg;
251 | unsigned long j = jiffies;
252 | seq_printf(data->m, "%9li %3li %i %6i %i %s\n",
253 | j, j - data->prevjiffies, in_interrupt() ? 1 : 0,
254 | current->pid, smp_processor_id(), current->comm);
255 |
256 | if (--data->loops) {
257 | data->prevjiffies = j;
258 | if (data->hi)
259 | tasklet_hi_schedule(&data->tlet);
260 | else
261 | tasklet_schedule(&data->tlet);
262 | } else {
263 | wake_up_interruptible(&data->wait);
264 | }
265 | }
266 |
267 | /* the /proc function: allocate everything to allow concurrency */
268 | int jit_tasklet_show(struct seq_file *m, void *v)
269 | {
270 | struct jit_data *data;
271 | unsigned long j = jiffies;
272 | long hi = (long)m->private;
273 |
274 | data = kmalloc(sizeof(*data), GFP_KERNEL);
275 | if (!data)
276 | return -ENOMEM;
277 |
278 | init_waitqueue_head(&data->wait);
279 |
280 | /* write the first lines in the buffer */
281 | seq_puts(m, " time delta inirq pid cpu command\n");
282 | seq_printf(m, "%9li %3li %i %6i %i %s\n",
283 | j, 0L, in_interrupt() ? 1 : 0,
284 | current->pid, smp_processor_id(), current->comm);
285 |
286 | /* fill the data for our tasklet function */
287 | data->prevjiffies = j;
288 | data->m = m;
289 | data->loops = JIT_ASYNC_LOOPS;
290 |
291 | /* register the tasklet */
292 | tasklet_init(&data->tlet, jit_tasklet_fn, (unsigned long)data);
293 | data->hi = hi;
294 | if (hi)
295 | tasklet_hi_schedule(&data->tlet);
296 | else
297 | tasklet_schedule(&data->tlet);
298 |
299 | /* wait for the buffer to fill */
300 | wait_event_interruptible(data->wait, !data->loops);
301 |
302 | if (signal_pending(current))
303 | return -ERESTARTSYS;
304 | kfree(data);
305 | return 0;
306 | }
307 |
308 | static int jit_tasklet_open(struct inode *inode, struct file *file)
309 | {
310 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)
311 | return single_open(file, jit_tasklet_show, PDE_DATA(inode));
312 | #else
313 | return single_open(file, jit_tasklet_show, pde_data(inode));
314 | #endif
315 | }
316 |
317 | static const struct file_operations jit_tasklet_fops = {
318 | .open = jit_tasklet_open,
319 | .read = seq_read,
320 | .llseek = seq_lseek,
321 | .release = single_release,
322 | };
323 |
324 | int __init jit_init(void)
325 | {
326 | proc_create("currentime", 0, NULL,
327 | proc_ops_wrapper(&jit_currentime_fops, jit_currentime_pops));
328 | proc_create_data("jitbusy", 0, NULL,
329 | proc_ops_wrapper(&jit_fn_fops, jit_fn_pops), (void *)JIT_BUSY);
330 | proc_create_data("jitsched", 0, NULL,
331 | proc_ops_wrapper(&jit_fn_fops, jit_fn_pops), (void *)JIT_SCHED);
332 | proc_create_data("jitqueue", 0, NULL,
333 | proc_ops_wrapper(&jit_fn_fops, jit_fn_pops), (void *)JIT_QUEUE);
334 | proc_create_data("jitschedto", 0, NULL,
335 | proc_ops_wrapper(&jit_fn_fops, jit_fn_pops), (void *)JIT_SCHEDTO);
336 |
337 | proc_create("jitimer", 0, NULL,
338 | proc_ops_wrapper(&jit_timer_fops, jit_timer_pops));
339 | proc_create("jitasklet", 0, NULL,
340 | proc_ops_wrapper(&jit_tasklet_fops, jit_tasklet_pops));
341 | proc_create_data("jitasklethi", 0, NULL,
342 | proc_ops_wrapper(&jit_tasklet_fops, jit_tasklet_pops), (void *)1);
343 |
344 | return 0; /* success */
345 | }
346 |
347 | void __exit jit_cleanup(void)
348 | {
349 | remove_proc_entry("currentime", NULL);
350 | remove_proc_entry("jitbusy", NULL);
351 | remove_proc_entry("jitsched", NULL);
352 | remove_proc_entry("jitqueue", NULL);
353 | remove_proc_entry("jitschedto", NULL);
354 |
355 | remove_proc_entry("jitimer", NULL);
356 | remove_proc_entry("jitasklet", NULL);
357 | remove_proc_entry("jitasklethi", NULL);
358 | }
359 |
360 | module_init(jit_init);
361 | module_exit(jit_cleanup);
362 |
--------------------------------------------------------------------------------
/misc-modules/kdataalign.c:
--------------------------------------------------------------------------------
1 | /*
2 | * kdatasize.c -- print the size of common data items from kernel space
3 | * This runs with any Linux kernel (not any Unix, because of )
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | /*
24 | * Define several data structures, all of them start with a lone char
25 | * in order to present an unaligned offset for the next field
26 | */
27 | struct c {char c; char t;} c;
28 | struct s {char c; short t;} s;
29 | struct i {char c; int t;} i;
30 | struct l {char c; long t;} l;
31 | struct ll {char c; long long t;} ll;
32 | struct p {char c; void * t;} p;
33 | struct u1b {char c; __u8 t;} u1b;
34 | struct u2b {char c; __u16 t;} u2b;
35 | struct u4b {char c; __u32 t;} u4b;
36 | struct u8b {char c; __u64 t;} u8b;
37 |
38 | static void data_cleanup(void)
39 | {
40 | /* never called */
41 | }
42 |
43 | static int data_init(void)
44 | {
45 | /* print information and return an error */
46 | printk("arch Align: char short int long ptr long-long "
47 | " u8 u16 u32 u64\n");
48 | printk("%-12s %3i %3i %3i %3i %3i %3i "
49 | "%3i %3i %3i %3i\n",
50 | init_uts_ns.name.machine,
51 | /* note that gcc can subtract void * values, but it's not ansi */
52 | (int)((void *)(&c.t) - (void *)&c),
53 | (int)((void *)(&s.t) - (void *)&s),
54 | (int)((void *)(&i.t) - (void *)&i),
55 | (int)((void *)(&l.t) - (void *)&l),
56 | (int)((void *)(&p.t) - (void *)&p),
57 | (int)((void *)(&ll.t) - (void *)&ll),
58 | (int)((void *)(&u1b.t) - (void *)&u1b),
59 | (int)((void *)(&u2b.t) - (void *)&u2b),
60 | (int)((void *)(&u4b.t) - (void *)&u4b),
61 | (int)((void *)(&u8b.t) - (void *)&u8b));
62 | return -ENODEV;
63 | }
64 |
65 | module_init(data_init);
66 | module_exit(data_cleanup);
67 |
68 | MODULE_LICENSE("Dual BSD/GPL");
69 |
--------------------------------------------------------------------------------
/misc-modules/kdatasize.c:
--------------------------------------------------------------------------------
1 | /*
2 | * kdatasize.c -- print the size of common data items from kernel space
3 | * This runs with any Linux kernel (not any Unix, because of )
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 |
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | static void data_cleanup(void)
25 | {
26 | /* never called */
27 | }
28 |
29 | int data_init(void)
30 | {
31 | /* print information and return an error */
32 | printk("arch Size: char short int long ptr long-long "
33 | " u8 u16 u32 u64\n");
34 | printk("%-12s %3i %3i %3i %3i %3i %3i "
35 | "%3i %3i %3i %3i\n",
36 | init_uts_ns.name.machine,
37 | (int)sizeof(char), (int)sizeof(short), (int)sizeof(int),
38 | (int)sizeof(long),
39 | (int)sizeof(void *), (int)sizeof(long long), (int)sizeof(__u8),
40 | (int)sizeof(__u16), (int)sizeof(__u32), (int)sizeof(__u64));
41 | return -ENODEV;
42 | }
43 |
44 | module_init(data_init);
45 | module_exit(data_cleanup);
46 |
47 | MODULE_LICENSE("Dual BSD/GPL");
48 |
--------------------------------------------------------------------------------
/misc-modules/module_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module=$1
3 | # Use the same name for the device as the name used for the module
4 | device=$1
5 | # Support read/write for owner and group, read only for everyone using 644
6 | mode="664"
7 |
8 | if [ $# -ne 1 ]; then
9 | echo "Wrong number of arguments"
10 | echo "usage: $0 module_name"
11 | echo "Will create a corresponding device /dev/module_name associated with module_name.ko"
12 | exit 1
13 | fi
14 |
15 | set -e
16 | # Group: since distributions do it differently, look for wheel or use staff
17 | # These are groups which correspond to system administrator accounts
18 | if grep -q '^staff:' /etc/group; then
19 | group="staff"
20 | else
21 | group="wheel"
22 | fi
23 |
24 | # Discard the module name before passing arguments to insmod
25 | shift
26 |
27 | echo "Load our module, exit on failure"
28 | insmod ./$module.ko $* || exit 1
29 | echo "Get the major number (allocated with allocate_chrdev_region) from /proc/devices"
30 | major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
31 | if [ ! -z ${major} ]; then
32 | echo "Remove any existing /dev node for /dev/${device}"
33 | rm -f /dev/${device}
34 | echo "Add a node for our device at /dev/${device} using mknod"
35 | mknod /dev/${device} c $major 0
36 | echo "Change group owner to ${group}"
37 | chgrp $group /dev/${device}
38 | echo "Change access mode to ${mode}"
39 | chmod $mode /dev/${device}
40 | else
41 | echo "No device found in /proc/devices for driver ${module} (this driver may not allocate a device)"
42 | fi
43 |
--------------------------------------------------------------------------------
/misc-modules/module_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module=$1
3 | device=$1
4 |
5 | if [ $# -ne 1 ]; then
6 | echo "Wrong number of arguments"
7 | echo "usage: $0 module_name"
8 | echo "Will unload the module specified by module_name and remove assocaited device"
9 | exit 1
10 | fi
11 |
12 | # invoke rmmod with all arguments we got
13 | rmmod $module || exit 1
14 |
15 | # Remove stale nodes
16 |
17 | rm -f /dev/${device}
18 |
--------------------------------------------------------------------------------
/misc-modules/seq.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple demonstration of the seq_file interface.
3 | *
4 | * seq.c,v 1.3 2004/09/26 07:02:43 gregkh Exp
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "proc_ops_version.h"
15 |
16 | MODULE_AUTHOR("Jonathan Corbet");
17 | MODULE_LICENSE("Dual BSD/GPL");
18 |
19 |
20 |
21 | /*
22 | * The sequence iterator functions. The position as seen by the
23 | * filesystem is just the count that we return.
24 | */
25 | static void *ct_seq_start(struct seq_file *s, loff_t *pos)
26 | {
27 | loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
28 | if (!spos)
29 | return NULL;
30 | *spos = *pos;
31 | return spos;
32 | }
33 |
34 | static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
35 | {
36 | loff_t *spos = (loff_t *) v;
37 | *pos = ++(*spos);
38 | return spos;
39 | }
40 |
41 | static void ct_seq_stop(struct seq_file *s, void *v)
42 | {
43 | kfree(v);
44 | }
45 |
46 | /*
47 | * The show function.
48 | */
49 | static int ct_seq_show(struct seq_file *s, void *v)
50 | {
51 | loff_t *spos = (loff_t *) v;
52 | seq_printf(s, "%lld\n", *spos);
53 | return 0;
54 | }
55 |
56 | /*
57 | * Tie them all together into a set of seq_operations.
58 | */
59 | static const struct seq_operations ct_seq_ops = {
60 | .start = ct_seq_start,
61 | .next = ct_seq_next,
62 | .stop = ct_seq_stop,
63 | .show = ct_seq_show
64 | };
65 |
66 |
67 | /*
68 | * Time to set up the file operations for our /proc file. In this case,
69 | * all we need is an open function which sets up the sequence ops.
70 | */
71 |
72 | static int ct_open(struct inode *inode, struct file *file)
73 | {
74 | return seq_open(file, &ct_seq_ops);
75 | };
76 |
77 | /*
78 | * The file operations structure contains our open function along with
79 | * set of the canned seq_ ops.
80 | */
81 | static const struct file_operations ct_file_ops = {
82 | .owner = THIS_MODULE,
83 | .open = ct_open,
84 | .read = seq_read,
85 | .llseek = seq_lseek,
86 | .release = seq_release
87 | };
88 |
89 |
90 | /*
91 | * Module setup and teardown.
92 | */
93 |
94 | static int ct_init(void)
95 | {
96 | struct proc_dir_entry *entry;
97 |
98 | entry = proc_create("sequence", 0, NULL,
99 | proc_ops_wrapper(&ct_file_ops, ct_file_pops));
100 | if (!entry)
101 | return -ENOMEM;
102 | return 0;
103 | }
104 |
105 | static void ct_exit(void)
106 | {
107 | remove_proc_entry("sequence", NULL);
108 | }
109 |
110 | module_init(ct_init);
111 | module_exit(ct_exit);
112 |
--------------------------------------------------------------------------------
/misc-modules/silly.c:
--------------------------------------------------------------------------------
1 | /*
2 | * silly.c -- Simple Tool for Unloading and Printing ISA Data
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: silly.c,v 1.3 2004/09/26 07:02:43 gregkh Exp $
16 | */
17 |
18 | /* =========================> BIG FAT WARNING:
19 | * This will only work on architectures with an ISA memory range.
20 | * It won't work on other computers.
21 | */
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include
29 | #include /* printk() */
30 | #include /* everything... */
31 | #include /* error codes */
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #include
38 | #include
39 |
40 | int silly_major = 0;
41 | module_param(silly_major, int, 0);
42 | MODULE_AUTHOR("Alessandro Rubini");
43 | MODULE_LICENSE("Dual BSD/GPL");
44 |
45 | /*
46 | * The devices access the 640k-1M memory.
47 | * minor 0 uses ioread8/iowrite8
48 | * minor 1 uses ioread16/iowrite16
49 | * minor 2 uses ioread32/iowrite32
50 | * minor 3 uses memcpy_fromio()/memcpy_toio()
51 | */
52 |
53 | /*
54 | * Here's our address range, and a place to store the ioremap'd base.
55 | */
56 | #define ISA_BASE 0xA0000
57 | #define ISA_MAX 0x100000 /* for general memory access */
58 |
59 | #define VIDEO_MAX 0xC0000 /* for vga access */
60 | #define VGA_BASE 0xb8000
61 | static void __iomem *io_base;
62 |
63 |
64 |
65 | int silly_open(struct inode *inode, struct file *filp)
66 | {
67 | return 0;
68 | }
69 |
70 | int silly_release(struct inode *inode, struct file *filp)
71 | {
72 | return 0;
73 | }
74 |
75 | enum silly_modes {M_8=0, M_16, M_32, M_memcpy};
76 |
77 | ssize_t silly_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
78 | {
79 | int retval;
80 | int mode = iminor(file_dentry(filp)->d_inode);
81 | void __iomem *add;
82 | unsigned long isa_addr = ISA_BASE + *f_pos;
83 | unsigned char *kbuf, *ptr;
84 |
85 | if (isa_addr + count > ISA_MAX) /* range: 0xA0000-0x100000 */
86 | count = ISA_MAX - isa_addr;
87 |
88 | /*
89 | * too big an f_pos (caused by a malicious lseek())
90 | * would result in a negative count
91 | */
92 | if (count < 0)
93 | return 0;
94 |
95 | kbuf = kmalloc(count, GFP_KERNEL);
96 | if (!kbuf)
97 | return -ENOMEM;
98 | ptr = kbuf;
99 | retval = count;
100 | /*
101 | * Convert our address into our remapped area.
102 | */
103 | add = (void __iomem *)(io_base + (isa_addr - ISA_BASE));
104 | /*
105 | * kbuf is aligned, but the reads might not. In order not to
106 | * drive me mad with unaligned leading and trailing bytes,
107 | * I downgrade the `mode' if unaligned xfers are requested.
108 | */
109 |
110 | if (mode == M_32 && ((isa_addr | count) & 3))
111 | mode = M_16;
112 | if (mode == M_16 && ((isa_addr | count) & 1))
113 | mode = M_8;
114 |
115 | switch(mode) {
116 | case M_32:
117 | while (count >= 4) {
118 | *(u32 *)ptr = ioread32(add);
119 | add += 4;
120 | count -= 4;
121 | ptr += 4;
122 | }
123 | break;
124 |
125 | case M_16:
126 | while (count >= 2) {
127 | *(u16 *)ptr = ioread16(add);
128 | add+=2;
129 | count-=2;
130 | ptr+=2;
131 | }
132 | break;
133 |
134 | case M_8:
135 | while (count) {
136 | *ptr = ioread8(add);
137 | add++;
138 | count--;
139 | ptr++;
140 | }
141 | break;
142 |
143 | case M_memcpy:
144 | memcpy_fromio(ptr, add, count);
145 | break;
146 |
147 | default:
148 | return -EINVAL;
149 | }
150 | if ((retval > 0) && copy_to_user(buf, kbuf, retval))
151 | retval = -EFAULT;
152 | kfree(kbuf);
153 | *f_pos += retval;
154 | return retval;
155 | }
156 |
157 |
158 | ssize_t silly_write(struct file *filp, const char __user *buf, size_t count,
159 | loff_t *f_pos)
160 | {
161 | int retval;
162 | int mode = iminor(file_dentry(filp)->d_inode);
163 | unsigned long isa_addr = ISA_BASE + *f_pos;
164 | unsigned char *kbuf, *ptr;
165 | void __iomem *add;
166 |
167 | /*
168 | * Writing is dangerous.
169 | * Allow root-only, independently of device permissions
170 | */
171 | if (!capable(CAP_SYS_RAWIO))
172 | return -EPERM;
173 |
174 | if (isa_addr + count > ISA_MAX) /* range: 0xA0000-0x100000 */
175 | count = ISA_MAX - isa_addr;
176 |
177 | /*
178 | * too big an f_pos (caused by a malicious lseek())
179 | * results in a negative count
180 | */
181 | if (count < 0)
182 | return 0;
183 |
184 | kbuf = kmalloc(count, GFP_KERNEL);
185 | if (!kbuf)
186 | return -ENOMEM;
187 | ptr = kbuf;
188 | retval=count;
189 |
190 | /*
191 | * kbuf is aligned, but the writes might not. In order not to
192 | * drive me mad with unaligned leading and trailing bytes,
193 | * I downgrade the `mode' if unaligned xfers are requested.
194 | */
195 |
196 | if (mode == M_32 && ((isa_addr | count) & 3))
197 | mode = M_16;
198 | if (mode == M_16 && ((isa_addr | count) & 1))
199 | mode = M_8;
200 |
201 | if (copy_from_user(kbuf, buf, count)) {
202 | kfree(kbuf);
203 | return -EFAULT;
204 | }
205 | ptr = kbuf;
206 |
207 | /*
208 | * Switch over to our remapped address space.
209 | */
210 | add = (void __iomem *)(io_base + (isa_addr - ISA_BASE));
211 |
212 | switch(mode) {
213 | case M_32:
214 | while (count >= 4) {
215 | iowrite8(*(u32 *)ptr, add);
216 | add += 4;
217 | count -= 4;
218 | ptr += 4;
219 | }
220 | break;
221 |
222 | case M_16:
223 | while (count >= 2) {
224 | iowrite8(*(u16 *)ptr, add);
225 | add += 2;
226 | count -= 2;
227 | ptr += 2;
228 | }
229 | break;
230 |
231 | case M_8:
232 | while (count) {
233 | iowrite8(*ptr, add);
234 | add++;
235 | count--;
236 | ptr++;
237 | }
238 | break;
239 |
240 | case M_memcpy:
241 | memcpy_toio(add, ptr, count);
242 | break;
243 |
244 | default:
245 | return -EINVAL;
246 | }
247 | *f_pos += retval;
248 | kfree(kbuf);
249 | return retval;
250 | }
251 |
252 |
253 | unsigned int silly_poll(struct file *filp, poll_table *wait)
254 | {
255 | return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
256 | }
257 |
258 |
259 | struct file_operations silly_fops = {
260 | .read = silly_read,
261 | .write = silly_write,
262 | .poll = silly_poll,
263 | .open = silly_open,
264 | .release = silly_release,
265 | .owner = THIS_MODULE
266 | };
267 |
268 | int silly_init(void)
269 | {
270 | int result = register_chrdev(silly_major, "silly", &silly_fops);
271 | if (result < 0) {
272 | printk(KERN_INFO "silly: can't get major number\n");
273 | return result;
274 | }
275 | if (silly_major == 0)
276 | silly_major = result; /* dynamic */
277 | /*
278 | * Set up our I/O range.
279 | */
280 |
281 | /* this line appears in silly_init */
282 | io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE);
283 | return 0;
284 | }
285 |
286 | void silly_cleanup(void)
287 | {
288 | iounmap(io_base);
289 | unregister_chrdev(silly_major, "silly");
290 | }
291 |
292 |
293 | module_init(silly_init);
294 | module_exit(silly_cleanup);
295 |
--------------------------------------------------------------------------------
/misc-modules/sleepy.c:
--------------------------------------------------------------------------------
1 | /*
2 | * sleepy.c -- the writers awake the readers
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: sleepy.c,v 1.7 2004/09/26 07:02:43 gregkh Exp $
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include /* current and everything */
22 | #include /* printk() */
23 | #include /* everything... */
24 | #include /* size_t */
25 | #include
26 |
27 | MODULE_LICENSE("Dual BSD/GPL");
28 |
29 | static int sleepy_major = 0;
30 |
31 | static DECLARE_WAIT_QUEUE_HEAD(wq);
32 | static int flag = 0;
33 |
34 | static ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
35 | {
36 | printk(KERN_DEBUG "process %i (%s) going to sleep\n",
37 | current->pid, current->comm);
38 | wait_event_interruptible(wq, flag != 0);
39 | flag = 0;
40 | printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
41 | return 0; /* EOF */
42 | }
43 |
44 | static ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count,
45 | loff_t *pos)
46 | {
47 | printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
48 | current->pid, current->comm);
49 | flag = 1;
50 | wake_up_interruptible(&wq);
51 | return count; /* succeed, to avoid retrial */
52 | }
53 |
54 |
55 | struct file_operations sleepy_fops = {
56 | .owner = THIS_MODULE,
57 | .read = sleepy_read,
58 | .write = sleepy_write,
59 | };
60 |
61 |
62 | static int sleepy_init(void)
63 | {
64 | int result;
65 |
66 | /*
67 | * Register your major, and accept a dynamic number
68 | */
69 | result = register_chrdev(sleepy_major, "sleepy", &sleepy_fops);
70 | if (result < 0)
71 | return result;
72 | if (sleepy_major == 0)
73 | sleepy_major = result; /* dynamic */
74 | return 0;
75 | }
76 |
77 | static void sleepy_cleanup(void)
78 | {
79 | unregister_chrdev(sleepy_major, "sleepy");
80 | }
81 |
82 | module_init(sleepy_init);
83 | module_exit(sleepy_cleanup);
84 |
85 |
--------------------------------------------------------------------------------
/misc-progs/Makefile:
--------------------------------------------------------------------------------
1 |
2 | FILES = asynctest nbtest load50 mapcmp polltest mapper setlevel setconsole inp outp \
3 | datasize dataalign netifdebug
4 |
5 | CFLAGS = -O2 -fomit-frame-pointer -Wall
6 |
7 | all: $(FILES)
8 |
9 | clean:
10 | rm -f $(FILES) *~ core
11 |
12 |
--------------------------------------------------------------------------------
/misc-progs/asynctest.c:
--------------------------------------------------------------------------------
1 | /*
2 | * asynctest.c: use async notification to read stdin
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | */
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | int gotdata=0;
24 | void sighandler(int signo)
25 | {
26 | if (signo==SIGIO)
27 | gotdata++;
28 | return;
29 | }
30 |
31 | char buffer[4096];
32 |
33 | int main(int argc, char **argv)
34 | {
35 | int count;
36 | struct sigaction action;
37 |
38 | memset(&action, 0, sizeof(action));
39 | action.sa_handler = sighandler;
40 | action.sa_flags = 0;
41 |
42 | sigaction(SIGIO, &action, NULL);
43 |
44 | fcntl(STDIN_FILENO, F_SETOWN, getpid());
45 | fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);
46 |
47 | while(1) {
48 | /* this only returns if a signal arrives */
49 | sleep(86400); /* one day */
50 | if (!gotdata)
51 | continue;
52 | count=read(0, buffer, 4096);
53 | /* buggy: if avail data is more than 4kbytes... */
54 | count=write(1,buffer,count);
55 | gotdata=0;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/misc-progs/dataalign.c:
--------------------------------------------------------------------------------
1 | /*
2 | * dataalign.c -- show alignment needs
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * This runs with any Linux kernel (not any Unix, because of )
16 | */
17 | #include
18 | #include
19 | #include
20 |
21 | /*
22 | * Define several data structures, all of them start with a lone char
23 | * in order to present an unaligned offset for the next field
24 | */
25 | struct c {char c; char t;} c;
26 | struct s {char c; short t;} s;
27 | struct i {char c; int t;} i;
28 | struct l {char c; long t;} l;
29 | struct ll {char c; long long t;} ll;
30 | struct p {char c; void * t;} p;
31 | struct u1b {char c; __u8 t;} u1b;
32 | struct u2b {char c; __u16 t;} u2b;
33 | struct u4b {char c; __u32 t;} u4b;
34 | struct u8b {char c; __u64 t;} u8b;
35 |
36 | int main(int argc, char **argv)
37 | {
38 | struct utsname name;
39 |
40 | uname(&name); /* never fails :) */
41 | printf("arch Align: char short int long ptr long-long "
42 | " u8 u16 u32 u64\n");
43 | printf( "%-12s %3i %3i %3i %3i %3i %3i "
44 | "%3i %3i %3i %3i\n",
45 | name.machine,
46 | /* note that gcc can subtract void * values, but it's not ansi */
47 | (int)((void *)(&c.t) - (void *)&c),
48 | (int)((void *)(&s.t) - (void *)&s),
49 | (int)((void *)(&i.t) - (void *)&i),
50 | (int)((void *)(&l.t) - (void *)&l),
51 | (int)((void *)(&p.t) - (void *)&p),
52 | (int)((void *)(&ll.t) - (void *)&ll),
53 | (int)((void *)(&u1b.t) - (void *)&u1b),
54 | (int)((void *)(&u2b.t) - (void *)&u2b),
55 | (int)((void *)(&u4b.t) - (void *)&u4b),
56 | (int)((void *)(&u8b.t) - (void *)&u8b));
57 | return 0;
58 | }
59 |
--------------------------------------------------------------------------------
/misc-progs/datasize.c:
--------------------------------------------------------------------------------
1 | /*
2 | * datasize.c -- print the size of common data items
3 | * This runs with any Linux kernel (not any Unix, because of )
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 | #include
17 | #include
18 | #include
19 |
20 | int main(int argc, char **argv)
21 | {
22 | struct utsname name;
23 |
24 | uname(&name); /* never fails :) */
25 | printf("arch Size: char short int long ptr long-long "
26 | " u8 u16 u32 u64\n");
27 | printf( "%-12s %3i %3i %3i %3i %3i %3i "
28 | "%3i %3i %3i %3i\n",
29 | name.machine,
30 | (int)sizeof(char), (int)sizeof(short), (int)sizeof(int),
31 | (int)sizeof(long),
32 | (int)sizeof(void *), (int)sizeof(long long), (int)sizeof(__u8),
33 | (int)sizeof(__u16), (int)sizeof(__u32), (int)sizeof(__u64));
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/misc-progs/gdbline:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # $Id: gdbline,v 1.1 2004/08/02 16:27:55 corbet Exp $
4 | #
5 | # gdbline module image
6 | #
7 | # Outputs an add-symbol-file line suitable for pasting into gdb to examine
8 | # a loaded module.
9 | #
10 | cd /sys/module/$1/sections
11 | echo -n add-symbol-file $2 `/bin/cat .text`
12 |
13 | for section in .[a-z]* *; do
14 | if [ $section != ".text" ]; then
15 | echo " \\"
16 | echo -n " -s" $section `/bin/cat $section`
17 | fi
18 | done
19 | echo
20 |
--------------------------------------------------------------------------------
/misc-progs/inp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * inp.c -- read all the ports specified in hex on the command line.
3 | * The program uses the faster ioperm/iopl calls on x86, /dev/port
4 | * on other platforms. The program acts as inb/inw/inl according
5 | * to its own name
6 | *
7 | * Copyright (C) 1998,2000,2001 Alessandro Rubini
8 | *
9 | * This program is free software; you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation; either version 2 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with this program; if not, write to the Free Software
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include /* linux-specific */
34 |
35 | #ifdef __GLIBC__
36 | # include
37 | #endif
38 |
39 | #define PORT_FILE "/dev/port"
40 |
41 | char *prgname;
42 |
43 | #ifdef __i386__
44 | static int read_and_print_one(unsigned int port,int size)
45 | {
46 | static int iopldone = 0;
47 |
48 | if (port > 1024) {
49 | if (!iopldone && iopl(3)) {
50 | fprintf(stderr, "%s: iopl(): %s\n", prgname, strerror(errno));
51 | return 1;
52 | }
53 | iopldone++;
54 | } else if (ioperm(port,size,1)) {
55 | fprintf(stderr, "%s: ioperm(%x): %s\n", prgname,
56 | port, strerror(errno));
57 | return 1;
58 | }
59 |
60 | if (size == 4)
61 | printf("%04x: %08x\n", port, inl(port));
62 | else if (size == 2)
63 | printf("%04x: %04x\n", port, inw(port));
64 | else
65 | printf("%04x: %02x\n", port, inb(port));
66 | return 0;
67 | }
68 | #else /* not i386 */
69 |
70 | static int read_and_print_one(unsigned int port,int size)
71 | {
72 | static int fd = -1;
73 | unsigned char b; unsigned short w; unsigned int l;
74 |
75 | if (fd < 0)
76 | fd = open(PORT_FILE, O_RDONLY);
77 | if (fd < 0) {
78 | fprintf(stderr, "%s: %s: %s\n", prgname, PORT_FILE, strerror(errno));
79 | return 1;
80 | }
81 | lseek(fd, port, SEEK_SET);
82 |
83 | if (size == 4) {
84 | read(fd, &l, 4);
85 | printf("%04x: 0x%08x\n", port, l);
86 | } else if (size == 2) {
87 | read(fd, &w, 2);
88 | printf("%04x: 0x%04x\n", port, w & 0xffff);
89 | } else {
90 | read(fd, &b, 1);
91 | printf("%04x: 0x%02x\n", port, b & 0xff);
92 | }
93 | return 0;
94 | }
95 |
96 | #endif /* i386 */
97 |
98 |
99 | int main(int argc, char **argv)
100 | {
101 | unsigned int i, n, port, size, error = 0;
102 |
103 | prgname = argv[0];
104 | /* find the data size */
105 | switch (prgname[strlen(prgname)-1]) {
106 | case 'w': size = 2; break;
107 | case 'l': size = 4; break;
108 | case 'b': case 'p': default:
109 | size = 1;
110 | }
111 |
112 | setuid(0); /* if we're setuid, force it on */
113 | for (i = 1; i < argc; i++) {
114 | if ( sscanf(argv[i], "%x%n", &port, &n) < 1
115 | || n != strlen(argv[i]) ) {
116 | fprintf(stderr, "%s: argument \"%s\" is not a hex number\n",
117 | argv[0], argv[i]);
118 | error++; continue;
119 | }
120 | if (port & (size-1)) {
121 | fprintf(stderr, "%s: argument \"%s\" is not properly aligned\n",
122 | argv[0], argv[i]);
123 | error++; continue;
124 | }
125 | error += read_and_print_one(port, size);
126 | }
127 | exit (error ? 1 : 0);
128 | }
129 |
130 |
--------------------------------------------------------------------------------
/misc-progs/load50.c:
--------------------------------------------------------------------------------
1 | /*
2 | * load50.c -- a simple busy-looping tool.
3 | * Obviously, this runs with any kernel and any Unix
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | int main(int argc, char **argv)
22 | {
23 | int i, load=50;
24 |
25 | if (argc==2) {
26 | load=atoi(argv[1]);
27 | }
28 | printf("Bringing load to %i\n",load);
29 |
30 | for (i=0; i
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | static char *mapdev (const char *, unsigned long, unsigned long);
26 | #define PAGE_SIZE 4096
27 |
28 | /*
29 | * memcmp dev1 dev2 offset pages
30 | */
31 | int main (int argc, char **argv)
32 | {
33 | unsigned long offset, size, i;
34 | char *addr1, *addr2;
35 | /*
36 | * Sanity check.
37 | */
38 | if (argc != 5)
39 | {
40 | fprintf (stderr, "Usage: mapcmp dev1 dev2 offset pages\n");
41 | exit (1);
42 | }
43 | /*
44 | * Map the two devices.
45 | */
46 | offset = strtoul (argv[3], NULL, 16);
47 | size = atoi (argv[4])*PAGE_SIZE;
48 | printf ("Offset is 0x%lx\n", offset);
49 | addr1 = mapdev (argv[1], offset, size);
50 | addr2 = mapdev (argv[2], offset, size);
51 | /*
52 | * Do the comparison.
53 | */
54 | printf ("Comparing...");
55 | fflush (stdout);
56 | for (i = 0; i < size; i++)
57 | if (*addr1++ != *addr2++)
58 | {
59 | printf ("areas differ at byte %ld\n", i);
60 | exit (0);
61 | }
62 | printf ("areas are identical.\n");
63 | exit (0);
64 | }
65 |
66 |
67 |
68 | static char *mapdev (const char *dev, unsigned long offset,
69 | unsigned long size)
70 | {
71 | char *addr;
72 | int fd = open (dev, O_RDONLY);
73 |
74 | if (fd < 0)
75 | {
76 | perror (dev);
77 | exit (1);
78 | }
79 | addr = mmap (0, size, PROT_READ, MAP_PRIVATE, fd, offset);
80 | if (addr == MAP_FAILED)
81 | {
82 | perror (dev);
83 | exit (1);
84 | }
85 | printf ("Mapped %s (%lu @ %lx) at %p\n", dev, size, offset, addr);
86 | return (addr);
87 | }
88 |
--------------------------------------------------------------------------------
/misc-progs/mapper.c:
--------------------------------------------------------------------------------
1 | /*
2 | * mapper.c -- simple file that mmap()s a file region and prints it
3 | *
4 | * Copyright (C) 1998,2000,2001 Alessandro Rubini
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 2 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program; if not, write to the Free Software
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 | */
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | int main(int argc, char **argv)
30 | {
31 | char *fname;
32 | FILE *f;
33 | unsigned long offset, len;
34 | void *address;
35 |
36 | if (argc !=4
37 | || sscanf(argv[2],"%li", &offset) != 1
38 | || sscanf(argv[3],"%li", &len) != 1) {
39 | fprintf(stderr, "%s: Usage \"%s \"\n", argv[0],
40 | argv[0]);
41 | exit(1);
42 | }
43 | /* the offset might be big (e.g., PCI devices), but conversion trims it */
44 | if (offset == INT_MAX) {
45 | if (argv[2][1]=='x')
46 | sscanf(argv[2]+2, "%lx", &offset);
47 | else
48 | sscanf(argv[2], "%lu", &offset);
49 | }
50 |
51 | fname=argv[1];
52 |
53 | if (!(f=fopen(fname,"r"))) {
54 | fprintf(stderr, "%s: %s: %s\n", argv[0], fname, strerror(errno));
55 | exit(1);
56 | }
57 |
58 | address=mmap(0, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fileno(f), offset);
59 |
60 | if (address == (void *)-1) {
61 | fprintf(stderr,"%s: mmap(): %s\n",argv[0],strerror(errno));
62 | exit(1);
63 | }
64 | fclose(f);
65 | fprintf(stderr, "mapped \"%s\" from %lu (0x%08lx) to %lu (0x%08lx)\n",
66 | fname, offset, offset, offset+len, offset+len);
67 |
68 | fwrite(address, 1, len, stdout);
69 | return 0;
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/misc-progs/nbtest.c:
--------------------------------------------------------------------------------
1 | /*
2 | * nbtest.c: read and write in non-blocking mode
3 | * This should run with any Unix
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | char buffer[4096];
24 |
25 | int main(int argc, char **argv)
26 | {
27 | int delay = 1, n, m = 0;
28 |
29 | if (argc > 1)
30 | delay=atoi(argv[1]);
31 | fcntl(0, F_SETFL, fcntl(0,F_GETFL) | O_NONBLOCK); /* stdin */
32 | fcntl(1, F_SETFL, fcntl(1,F_GETFL) | O_NONBLOCK); /* stdout */
33 |
34 | while (1) {
35 | n = read(0, buffer, 4096);
36 | if (n >= 0)
37 | m = write(1, buffer, n);
38 | if ((n < 0 || m < 0) && (errno != EAGAIN))
39 | break;
40 | sleep(delay);
41 | }
42 | perror(n < 0 ? "stdin" : "stdout");
43 | exit(1);
44 | }
45 |
--------------------------------------------------------------------------------
/misc-progs/netifdebug.c:
--------------------------------------------------------------------------------
1 | /*
2 | * netifdebug.c -- change the IFF_DEBUG flag of an interface
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | */
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | int main(int argc, char **argv)
28 | {
29 | int action = -1, sock;
30 | struct ifreq req;
31 | char *actname;
32 |
33 | if (argc < 2) {
34 | fprintf(stderr,"%s: usage is \"%s []\"\n",
35 | argv[0],argv[0]);
36 | exit(1);
37 | }
38 | if (argc==2)
39 | actname="tell";
40 | else
41 | actname=argv[2];
42 |
43 | /* a silly raw socket just for ioctl()ling it */
44 | sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
45 | if (sock < 0) {
46 | fprintf(stderr, "%s: socket(): %s\n", argv[0],strerror(errno));
47 | exit(1);
48 | }
49 |
50 | /* retrieve flags */
51 | strcpy(req.ifr_name, argv[1]);
52 | if ( ioctl(sock, SIOCGIFFLAGS, &req) < 0) {
53 | fprintf(stderr, " %s: ioctl(SIOCGIFFLAGS): %s\n",
54 | argv[0],strerror(errno));
55 | exit(1);
56 | }
57 |
58 | if (!strcmp(actname,"on")
59 | || !strcmp(actname,"+")
60 | || !strcmp(actname,"1"))
61 | action = IFF_DEBUG;
62 |
63 | if (!strcmp(actname,"off")
64 | || !strcmp(actname,"-")
65 | || !strcmp(actname,"0"))
66 | action = 0;
67 |
68 | if (!strcmp(actname,"tell")
69 | || actname[0]=='t') {
70 | printf("%s: debug is %s\n", argv[1],
71 | req.ifr_flags & IFF_DEBUG ? "on" : "off");
72 | exit(0);
73 | }
74 |
75 | req.ifr_flags &= ~IFF_DEBUG;
76 | req.ifr_flags |= action;
77 |
78 | if ( ioctl(sock, SIOCSIFFLAGS, &req) < 0) {
79 | fprintf(stderr, " %s: ioctl(SIOCSIFFLAGS): %s\n",
80 | argv[0],strerror(errno));
81 | exit(1);
82 | }
83 | exit(0);
84 | }
85 |
--------------------------------------------------------------------------------
/misc-progs/outp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * outp.c -- write all the ports specified in hex on the command line.
3 | * The program uses the faster ioperm/iopl calls on x86, /dev/port
4 | * on other platforms. The program acts as outb/outw/outl according
5 | * to its own name
6 | *
7 | * Copyright (C) 1998,2000,2001 Alessandro Rubini
8 | *
9 | * This program is free software; you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation; either version 2 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with this program; if not, write to the Free Software
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include /* linux-specific */
34 |
35 | #ifdef __GLIBC__
36 | # include
37 | #endif
38 |
39 | #define PORT_FILE "/dev/port"
40 |
41 | char *prgname;
42 |
43 | #ifdef __i386__
44 | static int write_one(unsigned int port, unsigned int val, int size)
45 | {
46 | static int iopldone = 0;
47 |
48 | if (port > 1024) {
49 | if (!iopldone && iopl(3)) {
50 | fprintf(stderr, "%s: iopl(): %s\n", prgname, strerror(errno));
51 | return 1;
52 | }
53 | iopldone++;
54 | } else if (ioperm(port,size,1)) {
55 | fprintf(stderr, "%s: ioperm(%x): %s\n", prgname,
56 | port, strerror(errno));
57 | return 1;
58 | }
59 |
60 | if (size == 4)
61 | outl(val, port);
62 | else if (size == 2)
63 | outw(val&0xffff, port);
64 | else
65 | outb(val&0xff, port);
66 | return 0;
67 | }
68 | #else /* not i386 */
69 |
70 | static int write_one(unsigned int port, unsigned int val, int size)
71 | {
72 | static int fd = -1;
73 | unsigned char b; unsigned short w;
74 |
75 | if (fd < 0)
76 | fd = open(PORT_FILE, O_WRONLY);
77 | if (fd < 0) {
78 | fprintf(stderr, "%s: %s: %s\n", prgname, PORT_FILE, strerror(errno));
79 | return 1;
80 | }
81 | lseek(fd, port, SEEK_SET);
82 |
83 | if (size == 4) {
84 | write(fd, &val, 4);
85 | } else if (size == 2) {
86 | w = val;
87 | write(fd, &w, 2);
88 | } else {
89 | b = val;
90 | write(fd, &b, 1);
91 | }
92 | return 0;
93 | }
94 |
95 | #endif /* i386 */
96 |
97 | int main(int argc, char **argv)
98 | {
99 | unsigned int i, n, port, val, size, error = 0;
100 |
101 | prgname = argv[0];
102 | /* find the data size */
103 | switch (prgname[strlen(prgname)-1]) {
104 | case 'w': size = 2; break;
105 | case 'l': size = 4; break;
106 | case 'b': case 'p': default:
107 | size = 1;
108 | }
109 | setuid(0); /* if we're setuid, force it on */
110 | for (i=1;i (size == 1 ? 0xff : 0xffff)) {
129 | fprintf(stderr, "%s: argument \"%s\" out of range\n",
130 | argv[0], argv[i+1]);
131 | error++; continue;
132 | }
133 | error += write_one(port, val, size);
134 | }
135 | exit (error ? 1 : 0);
136 | }
137 |
--------------------------------------------------------------------------------
/misc-progs/polltest.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Test out reading with poll()
3 | * This should run with any Unix
4 | *
5 | * Copyright (C) 2003 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2003 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | *
16 | * $Id: polltest.c,v 1.1 2003/02/07 18:01:38 corbet Exp $
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | char buffer[4096];
27 |
28 | int main(int argc, char **argv)
29 | {
30 | struct pollfd pfd;
31 | int n;
32 |
33 | fcntl(0, F_SETFL, fcntl(0,F_GETFL) | O_NONBLOCK); /* stdin */
34 | pfd.fd = 0; /* stdin */
35 | pfd.events = POLLIN;
36 |
37 | while (1) {
38 | n=read(0, buffer, 4096);
39 | if (n >= 0)
40 | write(1, buffer, n);
41 | n = poll(&pfd, 1, -1);
42 | if (n < 0)
43 | break;
44 | }
45 | perror( n<0 ? "stdin" : "stdout");
46 | exit(1);
47 | }
48 |
--------------------------------------------------------------------------------
/misc-progs/setconsole.c:
--------------------------------------------------------------------------------
1 | /*
2 | * setconsole.c -- choose a console to receive kernel messages
3 | *
4 | * Copyright (C) 1998,2000,2001 Alessandro Rubini
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 2 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program; if not, write to the Free Software
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 | */
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | int main(int argc, char **argv)
29 | {
30 | char bytes[2] = {11,0}; /* 11 is the TIOCLINUX cmd number */
31 |
32 | if (argc==2) bytes[1] = atoi(argv[1]); /* the chosen console */
33 | else {
34 | fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
35 | }
36 | if (ioctl(STDIN_FILENO, TIOCLINUX, bytes)<0) { /* use stdin */
37 | fprintf(stderr,"%s: ioctl(stdin, TIOCLINUX): %s\n",
38 | argv[0], strerror(errno));
39 | exit(1);
40 | }
41 | exit(0);
42 | }
43 |
--------------------------------------------------------------------------------
/misc-progs/setlevel.c:
--------------------------------------------------------------------------------
1 | /*
2 | * setlevel.c -- choose a console_loglevel for the kernel
3 | *
4 | * Copyright (C) 1998,2000,2001 Alessandro Rubini
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 2 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program; if not, write to the Free Software
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 | */
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | /* #include */ /* conflicting on the alpha */
26 | #include
27 | #include
28 |
29 | int main(int argc, char **argv)
30 | {
31 | int level;
32 |
33 | if (argc == 2) {
34 | level = atoi(argv[1]); /* the chosen console */
35 | } else {
36 | fprintf(stderr, "%s: need a single arg\n", argv[0]); exit(1);
37 | }
38 |
39 | if (klogctl(8, NULL, level) < 0) {
40 | fprintf(stderr, "%s: syslog(setlevel): %s\n",
41 | argv[0], strerror(errno));
42 | exit(1);
43 | }
44 | exit(0);
45 | }
46 |
--------------------------------------------------------------------------------
/misc-progs/test/.gitignore:
--------------------------------------------------------------------------------
1 | infile
2 | outfile
3 |
--------------------------------------------------------------------------------
/misc-progs/test/nonblock.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | infile=infile
4 | delay=1
5 | outfile=outfile
6 | strace=
7 |
8 | function printusage
9 | {
10 | echo "Usage: $0 [-i infile] [-d delay ] [-o outfile] [-s]"
11 | echo " Writes outfile in non-blocking mode with the content of infile as it is updated"
12 | echo " polling for changes to the file after delay seconds"
13 | echo " When -s is specified, strace is used to trace the command"
14 | echo " device default is ${device}"
15 | echo " infile default is ${infile}"
16 | echo " delay default is ${delay} seconds"
17 | echo " See Linux Device Drivers 3rd Edition chapter 6 section \"Testing the Scullpipe Driver\""
18 | echo " For example, to test non blocking IO on /dev/scullpipe for both read and write, you can:"
19 | echo " Open one terminal window and enter command ./misc-progs/test/nonblock.sh -o /dev/scullpipe -s"
20 | echo " Open a second terminal window and enter command ./misc-progs/test/nonblock.sh -i /dev/scullpipe -s"
21 | echo " Open a 3rd terminal window and enter command tail -f ./misc-progs/test/outfile"
22 | echo " Open a 4th terminal window and ender command echo \"Hello World!\" >> ./misc-progs/test/infile"
23 | echo " * You should see continuous polling at the rate specified by the delay argument on each"
24 | echo " endpoint."
25 | echo " * You should see the output moved from infile to outfile as each echo command is sent"
26 | echo " * When building with DEBUG=y in the makefile, you should see debug messages in kern.log"
27 | echo " indicating the utility nbtest read/wrote bytes successfully"
28 | }
29 |
30 | while getopts "i:o:d:sh" opt; do
31 | case ${opt} in
32 | i )
33 | infile=$OPTARG
34 | ;;
35 | d )
36 | delay=$OPTARG
37 | ;;
38 | o )
39 | outfile=$OPTARG
40 | ;;
41 | s )
42 | strace=strace
43 | ;;
44 | h )
45 | printusage
46 | exit 0
47 | ;;
48 |
49 | \? )
50 | echo "Invalid option $OPTARG" 1>&2
51 | printusage
52 | exit 1
53 | ;;
54 | : )
55 | echo "Invalid option $OPTARG requires an argument" 1>&2
56 | printusage
57 | exit 1
58 | ;;
59 | esac
60 | done
61 |
62 | set -e
63 | cd `dirname $0`
64 | touch ${infile}
65 | echo "Reading content of ${infile} through non blocking test to ${outfile}"
66 | echo "${strace} ../nbtest ${delay} > ${outfile} < ${infile}"
67 | ${strace} ../nbtest ${delay} > ${outfile} < ${infile}
68 |
--------------------------------------------------------------------------------
/pci/Makefile:
--------------------------------------------------------------------------------
1 | obj-m := pci_skel.o
2 |
3 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
4 | PWD := $(shell pwd)
5 |
6 | all:
7 | $(MAKE) -C $(KERNELDIR) M=$(PWD)
8 |
9 | clean:
10 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers built-in.a
11 |
12 |
--------------------------------------------------------------------------------
/pci/pci_skel.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 |
7 | static struct pci_device_id ids[] = {
8 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3), },
9 | { 0, }
10 | };
11 | MODULE_DEVICE_TABLE(pci, ids);
12 |
13 | static unsigned char skel_get_revision(struct pci_dev *dev)
14 | {
15 | u8 revision;
16 |
17 | pci_read_config_byte(dev, PCI_REVISION_ID, &revision);
18 | return revision;
19 | }
20 |
21 | static int probe(struct pci_dev *dev, const struct pci_device_id *id)
22 | {
23 | /* Do probing type stuff here.
24 | * Like calling request_region();
25 | */
26 | if(pci_enable_device(dev)) {
27 | dev_err(&dev->dev, "can't enable PCI device\n");
28 | return -ENODEV;
29 | }
30 |
31 | if (skel_get_revision(dev) == 0x42)
32 | return -ENODEV;
33 |
34 |
35 | return 0;
36 | }
37 |
38 | static void remove(struct pci_dev *dev)
39 | {
40 | /* clean up any allocated resources and stuff here.
41 | * like call release_region();
42 | */
43 | }
44 |
45 | static struct pci_driver pci_driver = {
46 | .name = "pci_skel",
47 | .id_table = ids,
48 | .probe = probe,
49 | .remove = remove,
50 | };
51 |
52 | static int __init pci_skel_init(void)
53 | {
54 | return pci_register_driver(&pci_driver);
55 | }
56 |
57 | static void __exit pci_skel_exit(void)
58 | {
59 | pci_unregister_driver(&pci_driver);
60 | }
61 |
62 | MODULE_LICENSE("GPL");
63 |
64 | module_init(pci_skel_init);
65 | module_exit(pci_skel_exit);
66 |
--------------------------------------------------------------------------------
/sbull/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 |
5 | # Add your debugging flag (or not) to CFLAGS
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSBULL_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | EXTRA_CFLAGS += $(DEBFLAGS)
13 | # for case RM_SIMPLE fall through
14 | EXTRA_CFLAGS += -I.. -Wno-implicit-fallthrough
15 |
16 | ifneq ($(KERNELRELEASE),)
17 | # call from kernel build system
18 |
19 | obj-m := sbull.o
20 |
21 | else
22 |
23 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
24 | PWD := $(shell pwd)
25 |
26 | default:
27 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
28 |
29 | endif
30 |
31 |
32 |
33 | clean:
34 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
35 |
36 | depend .depend dep:
37 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
38 |
39 |
40 | ifeq (.depend,$(wildcard .depend))
41 | include .depend
42 | endif
43 |
--------------------------------------------------------------------------------
/sbull/sbull.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * sbull.h -- definitions for the char module
4 | *
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | *
16 | */
17 |
18 |
19 | #include
20 |
21 | /* Multiqueue only works on 2.4 */
22 | #ifdef SBULL_MULTIQUEUE
23 | # warning "Multiqueue only works on 2.4 kernels"
24 | #endif
25 |
26 | /*
27 | * Macros to help debugging
28 | */
29 |
30 | #undef PDEBUG /* undef it, just in case */
31 | #ifdef SBULL_DEBUG
32 | # ifdef __KERNEL__
33 | /* This one if debugging is on, and kernel space */
34 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "sbull: " fmt, ## args)
35 | # else
36 | /* This one for user space */
37 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
38 | # endif
39 | #else
40 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
41 | #endif
42 |
43 | #undef PDEBUGG
44 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
45 |
46 |
47 | #define SBULL_MAJOR 0 /* dynamic major by default */
48 | #define SBULL_DEVS 2 /* two disks */
49 | #define SBULL_RAHEAD 2 /* two sectors */
50 | #define SBULL_SIZE 2048 /* two megs each */
51 | #define SBULL_BLKSIZE 1024 /* 1k blocks */
52 | #define SBULL_HARDSECT 512 /* 2.2 and 2.4 can used different values */
53 |
54 | #define SBULLR_MAJOR 0 /* Dynamic major for raw device */
55 | /*
56 | * The sbull device is removable: if it is left closed for more than
57 | * half a minute, it is removed. Thus use a usage count and a
58 | * kernel timer
59 | */
60 |
61 | typedef struct Sbull_Dev {
62 | int size;
63 | int usage;
64 | struct timer_list timer;
65 | spinlock_t lock;
66 | u8 *data;
67 | #ifdef SBULL_MULTIQUEUE
68 | request_queue_t *queue;
69 | int busy;
70 | #endif
71 | } Sbull_Dev;
72 |
--------------------------------------------------------------------------------
/sbull/sbull_load:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function make_minors {
4 | let part=1
5 | while (($part < $minors)); do
6 | let minor=$part+$2
7 | mknod $1$part b $major $minor
8 | let part=$part+1
9 | done
10 | }
11 |
12 |
13 | # FIXME: This isn't handling minors (partitions) at all.
14 | module="sbull"
15 | device="sbull"
16 | mode="664"
17 | chardevice="sbullr"
18 | minors=16
19 |
20 | # Group: since distributions do it differently, look for wheel or use staff
21 | if grep '^staff:' /etc/group > /dev/null; then
22 | group="staff"
23 | else
24 | group="wheel"
25 | fi
26 |
27 | # invoke insmod with all arguments we got
28 | # and use a pathname, as newer modutils don't look in . by default
29 | insmod ./$module.ko $* || exit 1
30 |
31 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
32 |
33 | # Remove stale nodes and replace them, then give gid and perms
34 |
35 | rm -f /dev/${device}[a-d]* /dev/${device}
36 |
37 | mknod /dev/${device}a b $major 0
38 | make_minors /dev/${device}a 0
39 | mknod /dev/${device}b b $major 16
40 | make_minors /dev/${device}b 16
41 | mknod /dev/${device}c b $major 32
42 | make_minors /dev/${device}c 32
43 | mknod /dev/${device}d b $major 48
44 | make_minors /dev/${device}d 48
45 | ln -sf ${device}a /dev/${device}
46 | chgrp $group /dev/${device}[a-d]*
47 | chmod $mode /dev/${device}[a-d]*
48 |
--------------------------------------------------------------------------------
/sbull/sbull_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="sbull"
3 | device="sbull"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # Remove stale nodes
9 | rm -f /dev/${device}[a-d]* /dev/${device}
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/scull-shared/scull-async.c:
--------------------------------------------------------------------------------
1 | /*
2 | * scull-async.c
3 | *
4 | * Copyright (C) 2019 Dan Walkes
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include /* printk() */
21 | #include /* kmalloc() */
22 | #include /* everything... */
23 | #include /* error codes */
24 | #include /* size_t */
25 | #include
26 | #include
27 | #include /* O_ACCMODE */
28 | #include
29 | #include
30 | #include /* iov_iter* */
31 |
32 |
33 | /*
34 | * A simple asynchronous I/O implementation.
35 | */
36 |
37 | struct async_work {
38 | struct delayed_work work;
39 | struct kiocb *iocb;
40 | struct iov_iter *tofrom;
41 | };
42 |
43 | /*
44 | * "Complete" an asynchronous operation.
45 | */
46 | static void scull_do_deferred_op(struct work_struct *work)
47 | {
48 | struct async_work *stuff = container_of(work, struct async_work, work.work);
49 | if( iov_iter_rw(stuff->tofrom) == WRITE ) {
50 | generic_file_write_iter(stuff->iocb, stuff->tofrom);
51 | } else {
52 | generic_file_read_iter(stuff->iocb, stuff->tofrom);
53 | }
54 | kfree(stuff);
55 | }
56 |
57 |
58 | static int scull_defer_op(struct kiocb *iocb, struct iov_iter *tofrom)
59 | {
60 | struct async_work *stuff;
61 | int result;
62 | /* Otherwise defer the completion for a few milliseconds. */
63 | stuff = kmalloc (sizeof (*stuff), GFP_KERNEL);
64 | if (stuff == NULL)
65 | return result; /* No memory, just complete now */
66 | stuff->iocb = iocb;
67 | INIT_DELAYED_WORK(&stuff->work, scull_do_deferred_op);
68 | schedule_delayed_work(&stuff->work, HZ/100);
69 | return -EIOCBQUEUED;
70 | }
71 |
72 |
73 | ssize_t scull_read_iter(struct kiocb *iocb, struct iov_iter *to)
74 | {
75 | /* If this is a synchronous IOCB, we return our status now. */
76 | if (is_sync_kiocb(iocb)) {
77 | return generic_file_read_iter(iocb,to);
78 | }
79 | return scull_defer_op(iocb, to);
80 | }
81 |
82 | ssize_t scull_write_iter(struct kiocb *iocb, struct iov_iter *from)
83 | {
84 | if (is_sync_kiocb(iocb)) {
85 | return generic_file_write_iter(iocb,from);
86 | }
87 | return scull_defer_op(iocb, from);
88 | }
89 |
--------------------------------------------------------------------------------
/scull-shared/scull-async.h:
--------------------------------------------------------------------------------
1 | /*
2 | * scull-async.h
3 | *
4 | * Copyright (C) 2019 Dan Walkes
5 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
6 | * Copyright (C) 2001 O'Reilly & Associates
7 | *
8 | * The source code in this file can be freely used, adapted,
9 | * and redistributed in source or binary form, so long as an
10 | * acknowledgment appears in derived source files. The citation
11 | * should list that the code comes from the book "Linux Device
12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 | * by O'Reilly & Associates. No warranty is attached;
14 | * we cannot take responsibility for errors or fitness for use.
15 | */
16 |
17 | #ifndef SCULL_SHARED_SCULL_ASYNC_H_
18 | #define SCULL_SHARED_SCULL_ASYNC_H_
19 |
20 |
21 | ssize_t scull_write_iter(struct kiocb *iocb, struct iov_iter *from);
22 | ssize_t scull_read_iter(struct kiocb *iocb, struct iov_iter *to);
23 |
24 |
25 | #endif /* SCULL_SHARED_SCULL_ASYNC_H_ */
26 |
--------------------------------------------------------------------------------
/scull/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 |
5 | # Add your debugging flag (or not) to CFLAGS
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | LDDINC=$(PWD)/../include
13 |
14 | EXTRA_CFLAGS += $(DEBFLAGS)
15 | EXTRA_CFLAGS += -I$(LDDINC)
16 |
17 | ifneq ($(KERNELRELEASE),)
18 | # call from kernel build system
19 |
20 | scull-objs := main.o pipe.o access.o
21 |
22 | obj-m := scull.o
23 |
24 | else
25 |
26 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
27 | PWD := $(shell pwd)
28 |
29 | modules:
30 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
31 |
32 | endif
33 |
34 |
35 |
36 | clean:
37 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
38 |
39 | depend .depend dep:
40 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
41 |
42 |
43 | ifeq (.depend,$(wildcard .depend))
44 | include .depend
45 | endif
46 |
--------------------------------------------------------------------------------
/scull/scull.h:
--------------------------------------------------------------------------------
1 | /*
2 | * scull.h -- definitions for the char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: scull.h,v 1.15 2004/11/04 17:51:18 rubini Exp $
16 | */
17 |
18 | #ifndef _SCULL_H_
19 | #define _SCULL_H_
20 |
21 | #include /* needed for the _IOW etc stuff used later */
22 |
23 | /*
24 | * Macros to help debugging
25 | */
26 |
27 | #undef PDEBUG /* undef it, just in case */
28 | #ifdef SCULL_DEBUG
29 | # ifdef __KERNEL__
30 | /* This one if debugging is on, and kernel space */
31 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
32 | # else
33 | /* This one for user space */
34 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
35 | # endif
36 | #else
37 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
38 | #endif
39 |
40 | #undef PDEBUGG
41 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
42 |
43 | #ifndef SCULL_MAJOR
44 | #define SCULL_MAJOR 0 /* dynamic major by default */
45 | #endif
46 |
47 | #ifndef SCULL_NR_DEVS
48 | #define SCULL_NR_DEVS 4 /* scull0 through scull3 */
49 | #endif
50 |
51 | #ifndef SCULL_P_NR_DEVS
52 | #define SCULL_P_NR_DEVS 4 /* scullpipe0 through scullpipe3 */
53 | #endif
54 |
55 | /*
56 | * The bare device is a variable-length region of memory.
57 | * Use a linked list of indirect blocks.
58 | *
59 | * "scull_dev->data" points to an array of pointers, each
60 | * pointer refers to a memory area of SCULL_QUANTUM bytes.
61 | *
62 | * The array (quantum-set) is SCULL_QSET long.
63 | */
64 | #ifndef SCULL_QUANTUM
65 | #define SCULL_QUANTUM 4000
66 | #endif
67 |
68 | #ifndef SCULL_QSET
69 | #define SCULL_QSET 1000
70 | #endif
71 |
72 | /*
73 | * The pipe device is a simple circular buffer. Here its default size
74 | */
75 | #ifndef SCULL_P_BUFFER
76 | #define SCULL_P_BUFFER 4000
77 | #endif
78 |
79 | /*
80 | * Representation of scull quantum sets.
81 | */
82 | struct scull_qset {
83 | void **data;
84 | struct scull_qset *next;
85 | };
86 |
87 | struct scull_dev {
88 | struct scull_qset *data; /* Pointer to first quantum set */
89 | int quantum; /* the current quantum size */
90 | int qset; /* the current array size */
91 | unsigned long size; /* amount of data stored here */
92 | unsigned int access_key; /* used by sculluid and scullpriv */
93 | struct mutex lock; /* mutual exclusion semaphore */
94 | struct cdev cdev; /* Char device structure */
95 | };
96 |
97 | /*
98 | * Split minors in two parts
99 | */
100 | #define TYPE(minor) (((minor) >> 4) & 0xf) /* high nibble */
101 | #define NUM(minor) ((minor) & 0xf) /* low nibble */
102 |
103 |
104 | /*
105 | * The different configurable parameters
106 | */
107 | extern int scull_major; /* main.c */
108 | extern int scull_nr_devs;
109 | extern int scull_quantum;
110 | extern int scull_qset;
111 |
112 | extern int scull_p_buffer; /* pipe.c */
113 |
114 |
115 | /*
116 | * Prototypes for shared functions
117 | */
118 |
119 | int scull_p_init(dev_t dev);
120 | void scull_p_cleanup(void);
121 | int scull_access_init(dev_t dev);
122 | void scull_access_cleanup(void);
123 |
124 | int scull_trim(struct scull_dev *dev);
125 |
126 | ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
127 | loff_t *f_pos);
128 | ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
129 | loff_t *f_pos);
130 | loff_t scull_llseek(struct file *filp, loff_t off, int whence);
131 | long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
132 |
133 |
134 | /*
135 | * Ioctl definitions
136 | */
137 |
138 | /* Use 'k' as magic number */
139 | #define SCULL_IOC_MAGIC 'k'
140 | /* Please use a different 8-bit number in your code */
141 |
142 | #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0)
143 |
144 | /*
145 | * S means "Set" through a ptr,
146 | * T means "Tell" directly with the argument value
147 | * G means "Get": reply by setting through a pointer
148 | * Q means "Query": response is on the return value
149 | * X means "eXchange": switch G and S atomically
150 | * H means "sHift": switch T and Q atomically
151 | */
152 | #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int)
153 | #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int)
154 | #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3)
155 | #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4)
156 | #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int)
157 | #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int)
158 | #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7)
159 | #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8)
160 | #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)
161 | #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int)
162 | #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11)
163 | #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12)
164 |
165 | /*
166 | * The other entities only have "Tell" and "Query", because they're
167 | * not printed in the book, and there's no need to have all six.
168 | * (The previous stuff was only there to show different ways to do it.
169 | */
170 | #define SCULL_P_IOCTSIZE _IO(SCULL_IOC_MAGIC, 13)
171 | #define SCULL_P_IOCQSIZE _IO(SCULL_IOC_MAGIC, 14)
172 | /* ... more to come */
173 |
174 | #define SCULL_IOC_MAXNR 14
175 |
176 | #endif /* _SCULL_H_ */
177 |
--------------------------------------------------------------------------------
/scull/scull.init:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Sample init script for the scull driver module
3 |
4 | DEVICE="scull"
5 | SECTION="misc"
6 |
7 | # The list of filenames and minor numbers: $PREFIX is prefixed to all names
8 | PREFIX="scull"
9 | FILES=" 0 0 1 1 2 2 3 3 priv 16
10 | pipe0 32 pipe1 33 pipe2 34 pipe3 35
11 | single 48 uid 64 wuid 80"
12 |
13 | INSMOD=/sbin/insmod; # use /sbin/modprobe if you prefer
14 |
15 | function device_specific_post_load () {
16 | true; # fill at will
17 | }
18 | function device_specific_pre_unload () {
19 | true; # fill at will
20 | }
21 |
22 | # Everything below this line should work unchanged for any char device.
23 | # Obviously, however, no options on the command line: either in
24 | # /etc/${DEVICE}.conf or /etc/modules.conf (if modprobe is used)
25 |
26 | # Optional configuration file: format is
27 | # owner
28 | # group
29 | # mode
30 | # options
31 | CFG=/etc/${DEVICE}.conf
32 |
33 | # kernel version, used to look for modules
34 | KERNEL=`uname -r`
35 |
36 | #FIXME: it looks like there is no misc section. Where should it be?
37 | MODDIR="/lib/modules/${KERNEL}/kernel/drivers/${SECTION}"
38 | if [ ! -d $MODDIR ]; then MODDIR="/lib/modules/${KERNEL}/${SECTION}"; fi
39 |
40 | # Root or die
41 | if [ "$(id -u)" != "0" ]
42 | then
43 | echo "You must be root to load or unload kernel modules"
44 | exit 1
45 | fi
46 |
47 | # Read configuration file
48 | if [ -r $CFG ]; then
49 | OWNER=`awk "\\$1==\"owner\" {print \\$2}" $CFG`
50 | GROUP=`awk "\\$1==\"group\" {print \\$2}" $CFG`
51 | MODE=`awk "\\$1==\"mode\" {print \\$2}" $CFG`
52 | # The options string may include extra blanks or only blanks
53 | OPTIONS=`sed -n '/^options / s/options //p' $CFG`
54 | fi
55 |
56 |
57 | # Create device files
58 | function create_files () {
59 | cd /dev
60 | local devlist=""
61 | local file
62 | while true; do
63 | if [ $# -lt 2 ]; then break; fi
64 | file="${DEVICE}$1"
65 | mknod $file c $MAJOR $2
66 | devlist="$devlist $file"
67 | shift 2
68 | done
69 | if [ -n "$OWNER" ]; then chown $OWNER $devlist; fi
70 | if [ -n "$GROUP" ]; then chgrp $GROUP $devlist; fi
71 | if [ -n "$MODE" ]; then chmod $MODE $devlist; fi
72 | }
73 |
74 | # Remove device files
75 | function remove_files () {
76 | cd /dev
77 | local devlist=""
78 | local file
79 | while true; do
80 | if [ $# -lt 2 ]; then break; fi
81 | file="${DEVICE}$1"
82 | devlist="$devlist $file"
83 | shift 2
84 | done
85 | rm -f $devlist
86 | }
87 |
88 | # Load and create files
89 | function load_device () {
90 |
91 | if [ -f $MODDIR/$DEVICE.ko ]; then
92 | devpath=$MODDIR/$DEVICE.ko
93 | else if [ -f ./$DEVICE.ko ]; then
94 | devpath=./$DEVICE.ko
95 | else
96 | devpath=$DEVICE; # let insmod/modprobe guess
97 | fi; fi
98 | if [ "$devpath" != "$DEVICE" ]; then
99 | echo -n " (loading file $devpath)"
100 | fi
101 |
102 | if $INSMOD $devpath $OPTIONS; then
103 | MAJOR=`awk "\\$2==\"$DEVICE\" {print \\$1}" /proc/devices`
104 | remove_files $FILES
105 | create_files $FILES
106 | device_specific_post_load
107 | else
108 | echo " FAILED!"
109 | fi
110 | }
111 |
112 | # Unload and remove files
113 | function unload_device () {
114 | device_specific_pre_unload
115 | /sbin/rmmod $DEVICE
116 | remove_files $FILES
117 | }
118 |
119 |
120 | case "$1" in
121 | start)
122 | echo -n "Loading $DEVICE"
123 | load_device
124 | echo "."
125 | ;;
126 | stop)
127 | echo -n "Unloading $DEVICE"
128 | unload_device
129 | echo "."
130 | ;;
131 | force-reload|restart)
132 | echo -n "Reloading $DEVICE"
133 | unload_device
134 | load_device
135 | echo "."
136 | ;;
137 | *)
138 | echo "Usage: $0 {start|stop|restart|force-reload}"
139 | exit 1
140 | esac
141 |
142 | exit 0
143 |
--------------------------------------------------------------------------------
/scull/scull_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # $Id: scull_load,v 1.4 2004/11/03 06:19:49 rubini Exp $
3 | module="scull"
4 | device="scull"
5 | mode="664"
6 |
7 | # Group: since distributions do it differently, look for wheel or use staff
8 | if grep -q '^staff:' /etc/group; then
9 | group="staff"
10 | else
11 | group="wheel"
12 | fi
13 |
14 | # invoke insmod with all arguments we got
15 | # and use a pathname, as insmod doesn't look in . by default
16 | insmod ./$module.ko $* || exit 1
17 |
18 | # retrieve major number
19 | major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
20 |
21 | # Remove stale nodes and replace them, then give gid and perms
22 | # Usually the script is shorter, it's scull that has several devices in it.
23 |
24 | rm -f /dev/${device}[0-3]
25 | mknod /dev/${device}0 c $major 0
26 | mknod /dev/${device}1 c $major 1
27 | mknod /dev/${device}2 c $major 2
28 | mknod /dev/${device}3 c $major 3
29 | ln -sf ${device}0 /dev/${device}
30 | chgrp $group /dev/${device}[0-3]
31 | chmod $mode /dev/${device}[0-3]
32 |
33 | rm -f /dev/${device}pipe[0-3]
34 | mknod /dev/${device}pipe0 c $major 4
35 | mknod /dev/${device}pipe1 c $major 5
36 | mknod /dev/${device}pipe2 c $major 6
37 | mknod /dev/${device}pipe3 c $major 7
38 | ln -sf ${device}pipe0 /dev/${device}pipe
39 | chgrp $group /dev/${device}pipe[0-3]
40 | chmod $mode /dev/${device}pipe[0-3]
41 |
42 | rm -f /dev/${device}single
43 | mknod /dev/${device}single c $major 8
44 | chgrp $group /dev/${device}single
45 | chmod $mode /dev/${device}single
46 |
47 | rm -f /dev/${device}uid
48 | mknod /dev/${device}uid c $major 9
49 | chgrp $group /dev/${device}uid
50 | chmod $mode /dev/${device}uid
51 |
52 | rm -f /dev/${device}wuid
53 | mknod /dev/${device}wuid c $major 10
54 | chgrp $group /dev/${device}wuid
55 | chmod $mode /dev/${device}wuid
56 |
57 | rm -f /dev/${device}priv
58 | mknod /dev/${device}priv c $major 11
59 | chgrp $group /dev/${device}priv
60 | chmod $mode /dev/${device}priv
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/scull/scull_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scull"
3 | device="scull"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # Remove stale nodes
9 |
10 | rm -f /dev/${device} /dev/${device}[0-3]
11 | rm -f /dev/${device}priv
12 | rm -f /dev/${device}pipe /dev/${device}pipe[0-3]
13 | rm -f /dev/${device}single
14 | rm -f /dev/${device}uid
15 | rm -f /dev/${device}wuid
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/scullc/Makefile:
--------------------------------------------------------------------------------
1 |
2 | # Comment/uncomment the following line to enable/disable debugging
3 | #DEBUG = y
4 |
5 |
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULLC_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | LDDINC=$(PWD)/../include
13 | EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINC)
14 |
15 | TARGET = scullc
16 |
17 | ifneq ($(KERNELRELEASE),)
18 |
19 | scullc-objs := main.o scull-shared/scull-async.o
20 |
21 | obj-m := scullc.o
22 |
23 | else
24 |
25 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
26 | PWD := $(shell pwd)
27 |
28 | modules:
29 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
30 |
31 | endif
32 |
33 |
34 | install:
35 | install -d $(INSTALLDIR)
36 | install -c $(TARGET).o $(INSTALLDIR)
37 |
38 | clean:
39 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers scull-shared/scull-async.o
40 |
41 |
42 | depend .depend dep:
43 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
44 |
45 | ifeq (.depend,$(wildcard .depend))
46 | include .depend
47 | endif
48 |
--------------------------------------------------------------------------------
/scullc/mmap.c:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * mmap.c -- memory mapping for the scullc char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: _mmap.c.in,v 1.13 2004/10/18 18:07:36 corbet Exp $
16 | */
17 |
18 | #include
19 |
20 | #include /* everything */
21 | #include /* error codes */
22 | #include
23 |
24 | #include "scullc.h" /* local definitions */
25 |
26 |
27 | /*
28 | * open and close: just keep track of how many times the device is
29 | * mapped, to avoid releasing it.
30 | */
31 |
32 | void scullc_vma_open(struct vm_area_struct *vma)
33 | {
34 | struct scullc_dev *dev = vma->vm_private_data;
35 |
36 | dev->vmas++;
37 | }
38 |
39 | void scullc_vma_close(struct vm_area_struct *vma)
40 | {
41 | struct scullc_dev *dev = vma->vm_private_data;
42 |
43 | dev->vmas--;
44 | }
45 |
46 | /*
47 | * The nopage method: the core of the file. It retrieves the
48 | * page required from the scullc device and returns it to the
49 | * user. The count for the page must be incremented, because
50 | * it is automatically decremented at page unmap.
51 | *
52 | * For this reason, "order" must be zero. Otherwise, only the first
53 | * page has its count incremented, and the allocating module must
54 | * release it as a whole block. Therefore, it isn't possible to map
55 | * pages from a multipage block: when they are unmapped, their count
56 | * is individually decreased, and would drop to 0.
57 | */
58 |
59 | struct page *scullc_vma_nopage(struct vm_area_struct *vma,
60 | unsigned long address, int *type)
61 | {
62 | unsigned long offset;
63 | struct scullc_dev *ptr, *dev = vma->vm_private_data;
64 | struct page *page = NOPAGE_SIGBUS;
65 | void *pageptr = NULL; /* default to "missing" */
66 |
67 | mutex_lock(&dev->lock);
68 | offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
69 | if (offset >= dev->size) goto out; /* out of range */
70 |
71 | /*
72 | * Now retrieve the scullc device from the list,then the page.
73 | * If the device has holes, the process receives a SIGBUS when
74 | * accessing the hole.
75 | */
76 | offset >>= PAGE_SHIFT; /* offset is a number of pages */
77 | for (ptr = dev; ptr && offset >= dev->qset;) {
78 | ptr = ptr->next;
79 | offset -= dev->qset;
80 | }
81 | if (ptr && ptr->data) pageptr = ptr->data[offset];
82 | if (!pageptr) goto out; /* hole or end-of-file */
83 |
84 | /* got it, now increment the count */
85 | get_page(page);
86 | if (type)
87 | *type = VM_FAULT_MINOR;
88 | out:
89 | mutex_unlock(&dev->lock);
90 | return page;
91 | }
92 |
93 |
94 |
95 | struct vm_operations_struct scullc_vm_ops = {
96 | .open = scullc_vma_open,
97 | .close = scullc_vma_close,
98 | .nopage = scullc_vma_nopage,
99 | };
100 |
101 |
102 | int scullc_mmap(struct file *filp, struct vm_area_struct *vma)
103 | {
104 | struct inode *inode = filp->f_dentry->d_inode;
105 |
106 | /* refuse to map if order is not 0 */
107 | if (scullc_devices[iminor(inode)].order)
108 | return -ENODEV;
109 |
110 | /* don't do anything here: "nopage" will set up page table entries */
111 | vma->vm_ops = &scullc_vm_ops;
112 | vma->vm_private_data = filp->private_data;
113 | scullc_vma_open(vma);
114 | return 0;
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/scullc/scull-shared/scull-async.c:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.c
--------------------------------------------------------------------------------
/scullc/scull-shared/scull-async.h:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.h
--------------------------------------------------------------------------------
/scullc/scullc.h:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * scullc.h -- definitions for the scullc char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | */
15 |
16 | #include
17 | #include
18 |
19 | /*
20 | * Macros to help debugging
21 | */
22 |
23 | #undef PDEBUG /* undef it, just in case */
24 | #ifdef SCULLC_DEBUG
25 | # ifdef __KERNEL__
26 | /* This one if debugging is on, and kernel space */
27 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullc: " fmt, ## args)
28 | # else
29 | /* This one for user space */
30 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
31 | # endif
32 | #else
33 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
34 | #endif
35 |
36 | #undef PDEBUGG
37 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
38 |
39 | #define SCULLC_MAJOR 0 /* dynamic major by default */
40 |
41 | #define SCULLC_DEVS 4 /* scullc0 through scullc3 */
42 |
43 | /*
44 | * The bare device is a variable-length region of memory.
45 | * Use a linked list of indirect blocks.
46 | *
47 | * "scullc_dev->data" points to an array of pointers, each
48 | * pointer refers to a memory page.
49 | *
50 | * The array (quantum-set) is SCULLC_QSET long.
51 | */
52 | #define SCULLC_QUANTUM 4000 /* use a quantum size like scull */
53 | #define SCULLC_QSET 500
54 |
55 | struct scullc_dev {
56 | void **data;
57 | struct scullc_dev *next; /* next listitem */
58 | int vmas; /* active mappings */
59 | int quantum; /* the current allocation size */
60 | int qset; /* the current array size */
61 | size_t size; /* 32-bit will suffice */
62 | struct mutex lock; /* Mutual exclusion */
63 | struct cdev cdev;
64 | };
65 |
66 | extern struct scullc_dev *scullc_devices;
67 |
68 | extern struct file_operations scullc_fops;
69 |
70 | /*
71 | * The different configurable parameters
72 | */
73 | extern int scullc_major; /* main.c */
74 | extern int scullc_devs;
75 | extern int scullc_order;
76 | extern int scullc_qset;
77 |
78 | /*
79 | * Prototypes for shared functions
80 | */
81 | int scullc_trim(struct scullc_dev *dev);
82 | struct scullc_dev *scullc_follow(struct scullc_dev *dev, int n);
83 |
84 |
85 | #ifdef SCULLC_DEBUG
86 | # define SCULLC_USE_PROC
87 | #endif
88 |
89 | /*
90 | * Ioctl definitions
91 | */
92 |
93 | /* Use 'K' as magic number */
94 | #define SCULLC_IOC_MAGIC 'K'
95 |
96 | #define SCULLC_IOCRESET _IO(SCULLC_IOC_MAGIC, 0)
97 |
98 | /*
99 | * S means "Set" through a ptr,
100 | * T means "Tell" directly
101 | * G means "Get" (to a pointed var)
102 | * Q means "Query", response is on the return value
103 | * X means "eXchange": G and S atomically
104 | * H means "sHift": T and Q atomically
105 | */
106 | #define SCULLC_IOCSQUANTUM _IOW(SCULLC_IOC_MAGIC, 1, int)
107 | #define SCULLC_IOCTQUANTUM _IO(SCULLC_IOC_MAGIC, 2)
108 | #define SCULLC_IOCGQUANTUM _IOR(SCULLC_IOC_MAGIC, 3, int)
109 | #define SCULLC_IOCQQUANTUM _IO(SCULLC_IOC_MAGIC, 4)
110 | #define SCULLC_IOCXQUANTUM _IOWR(SCULLC_IOC_MAGIC, 5, int)
111 | #define SCULLC_IOCHQUANTUM _IO(SCULLC_IOC_MAGIC, 6)
112 | #define SCULLC_IOCSQSET _IOW(SCULLC_IOC_MAGIC, 7, int)
113 | #define SCULLC_IOCTQSET _IO(SCULLC_IOC_MAGIC, 8)
114 | #define SCULLC_IOCGQSET _IOR(SCULLC_IOC_MAGIC, 9, int)
115 | #define SCULLC_IOCQQSET _IO(SCULLC_IOC_MAGIC, 10)
116 | #define SCULLC_IOCXQSET _IOWR(SCULLC_IOC_MAGIC,11, int)
117 | #define SCULLC_IOCHQSET _IO(SCULLC_IOC_MAGIC, 12)
118 |
119 | #define SCULLC_IOC_MAXNR 12
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/scullc/scullc_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scullc"
3 | device="scullc"
4 | mode="664"
5 |
6 | # Group: since distributions do it differently, look for wheel or use staff
7 | if grep '^staff:' /etc/group > /dev/null; then
8 | group="staff"
9 | else
10 | group="wheel"
11 | fi
12 |
13 | # remove stale nodes
14 | rm -f /dev/${device}?
15 |
16 | # invoke insmod with all arguments we got
17 | # and use a pathname, as newer modutils don't look in . by default
18 | insmod ./$module.ko $* || exit 1
19 |
20 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
21 |
22 | mknod /dev/${device}0 c $major 0
23 | mknod /dev/${device}1 c $major 1
24 | mknod /dev/${device}2 c $major 2
25 | mknod /dev/${device}3 c $major 3
26 | ln -sf ${device}0 /dev/${device}
27 |
28 | # give appropriate group/permissions
29 | chgrp $group /dev/${device}[0-3]
30 | chmod $mode /dev/${device}[0-3]
31 |
--------------------------------------------------------------------------------
/scullc/scullc_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scullc"
3 | device="scullc"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # remove nodes
9 | rm -f /dev/${device}[0-3] /dev/${device}
10 |
11 | exit 0
12 |
--------------------------------------------------------------------------------
/sculld/Makefile:
--------------------------------------------------------------------------------
1 |
2 | # Comment/uncomment the following line to enable/disable debugging
3 | #DEBUG = y
4 |
5 |
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULLD_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | LDDINC=$(PWD)/../include
13 | EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINC)
14 |
15 | TARGET = sculld
16 |
17 | ifneq ($(KERNELRELEASE),)
18 |
19 | sculld-objs := main.o mmap.o scull-shared/scull-async.o
20 |
21 | obj-m := sculld.o
22 |
23 | else
24 |
25 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
26 | PWD := $(shell pwd)
27 |
28 | modules:
29 | echo "Copying Module.symvers to resolve lddbus exports"
30 | # cp $(PWD)/../lddbus/Module.symvers $(PWD)
31 | $(MAKE) -C $(KERNELDIR) M=$(PWD) KBUILD_EXTRA_SYMBOLS=$(PWD)/../lddbus/Module.symvers modules
32 |
33 | endif
34 |
35 |
36 | install:
37 | install -d $(INSTALLDIR)
38 | install -c $(TARGET).o $(INSTALLDIR)
39 |
40 | clean:
41 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers scull-shared/scull-async.o
42 |
43 |
44 | depend .depend dep:
45 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
46 |
47 | ifeq (.depend,$(wildcard .depend))
48 | include .depend
49 | endif
50 |
--------------------------------------------------------------------------------
/sculld/mmap.c:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * mmap.c -- memory mapping for the sculld char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: _mmap.c.in,v 1.13 2004/10/18 18:07:36 corbet Exp $
16 | */
17 |
18 | #include
19 | #include
20 | #include /* everything */
21 | #include /* error codes */
22 | #include
23 | #include
24 | #include "sculld.h" /* local definitions */
25 |
26 |
27 | /*
28 | * open and close: just keep track of how many times the device is
29 | * mapped, to avoid releasing it.
30 | */
31 |
32 | void sculld_vma_open(struct vm_area_struct *vma)
33 | {
34 | struct sculld_dev *dev = vma->vm_private_data;
35 |
36 | dev->vmas++;
37 | }
38 |
39 | void sculld_vma_close(struct vm_area_struct *vma)
40 | {
41 | struct sculld_dev *dev = vma->vm_private_data;
42 |
43 | dev->vmas--;
44 | }
45 |
46 | /*
47 | * The nopage method: the core of the file. It retrieves the
48 | * page required from the sculld device and returns it to the
49 | * user. The count for the page must be incremented, because
50 | * it is automatically decremented at page unmap.
51 | *
52 | * For this reason, "order" must be zero. Otherwise, only the first
53 | * page has its count incremented, and the allocating module must
54 | * release it as a whole block. Therefore, it isn't possible to map
55 | * pages from a multipage block: when they are unmapped, their count
56 | * is individually decreased, and would drop to 0.
57 | */
58 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
59 | typedef int vm_fault_t;
60 | #endif
61 | static vm_fault_t sculld_vma_nopage(struct vm_fault *vmf)
62 | {
63 | unsigned long offset;
64 | struct vm_area_struct *vma = vmf->vma;
65 | struct sculld_dev *ptr, *dev = vma->vm_private_data;
66 | struct page *page = NULL;
67 | void *pageptr = NULL; /* default to "missing" */
68 | vm_fault_t retval = VM_FAULT_NOPAGE;
69 |
70 | mutex_lock(&dev->mutex);
71 | offset = (unsigned long)(vmf->address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
72 | if (offset >= dev->size) goto out; /* out of range */
73 |
74 | /*
75 | * Now retrieve the sculld device from the list,then the page.
76 | * If the device has holes, the process receives a SIGBUS when
77 | * accessing the hole.
78 | */
79 | offset >>= PAGE_SHIFT; /* offset is a number of pages */
80 | for (ptr = dev; ptr && offset >= dev->qset;) {
81 | ptr = ptr->next;
82 | offset -= dev->qset;
83 | }
84 | if (ptr && ptr->data) pageptr = ptr->data[offset];
85 | if (!pageptr) goto out; /* hole or end-of-file */
86 |
87 | /* got it, now increment the count */
88 | get_page(page);
89 | vmf->page = page;
90 | retval = 0;
91 |
92 | out:
93 | mutex_unlock(&dev->mutex);
94 | return retval;
95 | }
96 |
97 |
98 |
99 | struct vm_operations_struct sculld_vm_ops = {
100 | .open = sculld_vma_open,
101 | .close = sculld_vma_close,
102 | .fault = sculld_vma_nopage,
103 | };
104 |
105 |
106 | int sculld_mmap(struct file *filp, struct vm_area_struct *vma)
107 | {
108 | struct inode *inode = filp->f_path.dentry->d_inode;
109 |
110 | /* refuse to map if order is not 0 */
111 | if (sculld_devices[iminor(inode)].order)
112 | return -ENODEV;
113 |
114 | /* don't do anything here: "nopage" will set up page table entries */
115 | vma->vm_ops = &sculld_vm_ops;
116 | vma->vm_private_data = filp->private_data;
117 | sculld_vma_open(vma);
118 | return 0;
119 | }
120 |
121 |
--------------------------------------------------------------------------------
/sculld/scull-shared/scull-async.c:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.c
--------------------------------------------------------------------------------
/sculld/scull-shared/scull-async.h:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.h
--------------------------------------------------------------------------------
/sculld/sculld.h:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * sculld.h -- definitions for the sculld char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | */
15 |
16 | #include
17 | #include
18 | #include
19 | #include "../include/lddbus.h"
20 |
21 | /*
22 | * Macros to help debugging
23 | */
24 |
25 | #undef PDEBUG /* undef it, just in case */
26 | #ifdef SCULLD_DEBUG
27 | # ifdef __KERNEL__
28 | /* This one if debugging is on, and kernel space */
29 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "sculld: " fmt, ## args)
30 | # else
31 | /* This one for user space */
32 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
33 | # endif
34 | #else
35 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
36 | #endif
37 |
38 | #undef PDEBUGG
39 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
40 |
41 | #define SCULLD_MAJOR 0 /* dynamic major by default */
42 |
43 | #define SCULLD_DEVS 4 /* sculld0 through sculld3 */
44 |
45 | /*
46 | * The bare device is a variable-length region of memory.
47 | * Use a linked list of indirect blocks.
48 | *
49 | * "sculld_dev->data" points to an array of pointers, each
50 | * pointer refers to a memory page.
51 | *
52 | * The array (quantum-set) is SCULLD_QSET long.
53 | */
54 | #define SCULLD_ORDER 0 /* one page at a time */
55 | #define SCULLD_QSET 500
56 |
57 | struct sculld_dev {
58 | void **data;
59 | struct sculld_dev *next; /* next listitem */
60 | int vmas; /* active mappings */
61 | int order; /* the current allocation order */
62 | int qset; /* the current array size */
63 | size_t size; /* 32-bit will suffice */
64 | struct mutex mutex; /* Mutual exclusion */
65 | struct cdev cdev;
66 | char devname[20];
67 | struct ldd_device ldev;
68 | };
69 |
70 | extern struct sculld_dev *sculld_devices;
71 |
72 | extern struct file_operations sculld_fops;
73 |
74 | /*
75 | * The different configurable parameters
76 | */
77 | extern int sculld_major; /* main.c */
78 | extern int sculld_devs;
79 | extern int sculld_order;
80 | extern int sculld_qset;
81 |
82 | /*
83 | * Prototypes for shared functions
84 | */
85 | int sculld_trim(struct sculld_dev *dev);
86 | struct sculld_dev *sculld_follow(struct sculld_dev *dev, int n);
87 |
88 |
89 | #ifdef SCULLD_DEBUG
90 | # define SCULLD_USE_PROC
91 | #endif
92 |
93 | /*
94 | * Ioctl definitions
95 | */
96 |
97 | /* Use 'K' as magic number */
98 | #define SCULLD_IOC_MAGIC 'K'
99 |
100 | #define SCULLD_IOCRESET _IO(SCULLD_IOC_MAGIC, 0)
101 |
102 | /*
103 | * S means "Set" through a ptr,
104 | * T means "Tell" directly
105 | * G means "Get" (to a pointed var)
106 | * Q means "Query", response is on the return value
107 | * X means "eXchange": G and S atomically
108 | * H means "sHift": T and Q atomically
109 | */
110 | #define SCULLD_IOCSORDER _IOW(SCULLD_IOC_MAGIC, 1, int)
111 | #define SCULLD_IOCTORDER _IO(SCULLD_IOC_MAGIC, 2)
112 | #define SCULLD_IOCGORDER _IOR(SCULLD_IOC_MAGIC, 3, int)
113 | #define SCULLD_IOCQORDER _IO(SCULLD_IOC_MAGIC, 4)
114 | #define SCULLD_IOCXORDER _IOWR(SCULLD_IOC_MAGIC, 5, int)
115 | #define SCULLD_IOCHORDER _IO(SCULLD_IOC_MAGIC, 6)
116 | #define SCULLD_IOCSQSET _IOW(SCULLD_IOC_MAGIC, 7, int)
117 | #define SCULLD_IOCTQSET _IO(SCULLD_IOC_MAGIC, 8)
118 | #define SCULLD_IOCGQSET _IOR(SCULLD_IOC_MAGIC, 9, int)
119 | #define SCULLD_IOCQQSET _IO(SCULLD_IOC_MAGIC, 10)
120 | #define SCULLD_IOCXQSET _IOWR(SCULLD_IOC_MAGIC,11, int)
121 | #define SCULLD_IOCHQSET _IO(SCULLD_IOC_MAGIC, 12)
122 |
123 | #define SCULLD_IOC_MAXNR 12
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/sculld/sculld_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="sculld"
3 | device="sculld"
4 | mode="664"
5 |
6 | # Group: since distributions do it differently, look for wheel or use staff
7 | if grep '^staff:' /etc/group > /dev/null; then
8 | group="staff"
9 | else
10 | group="wheel"
11 | fi
12 |
13 | # remove stale nodes
14 | rm -f /dev/${device}?
15 |
16 | # invoke insmod with all arguments we got
17 | # and use a pathname, as newer modutils don't look in . by default
18 | insmod ../lddbus/lddbus.ko $* || exit 1
19 | insmod ./$module.ko $* || exit 1
20 |
21 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
22 |
23 | mknod /dev/${device}0 c $major 0
24 | mknod /dev/${device}1 c $major 1
25 | mknod /dev/${device}2 c $major 2
26 | mknod /dev/${device}3 c $major 3
27 | ln -sf ${device}0 /dev/${device}
28 |
29 | # give appropriate group/permissions
30 | chgrp $group /dev/${device}[0-3]
31 | chmod $mode /dev/${device}[0-3]
32 |
--------------------------------------------------------------------------------
/sculld/sculld_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="sculld"
3 | device="sculld"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 | rmmod lddbus $* || exit 1
8 |
9 | # remove nodes
10 | rm -f /dev/${device}[0-3] /dev/${device}
11 |
12 | exit 0
13 |
--------------------------------------------------------------------------------
/scullp/Makefile:
--------------------------------------------------------------------------------
1 |
2 | # Comment/uncomment the following line to enable/disable debugging
3 | #DEBUG = y
4 |
5 |
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULLP_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | LDDINC=$(PWD)/../include
13 | EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINC)
14 |
15 | TARGET = scullp
16 |
17 | ifneq ($(KERNELRELEASE),)
18 |
19 | scullp-objs := main.o mmap.o scull-shared/scull-async.o
20 |
21 | obj-m := scullp.o
22 |
23 | else
24 |
25 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
26 | PWD := $(shell pwd)
27 |
28 | modules:
29 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
30 |
31 | endif
32 |
33 |
34 | install:
35 | install -d $(INSTALLDIR)
36 | install -c $(TARGET).o $(INSTALLDIR)
37 |
38 | clean:
39 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers scull-shared/scull-async.o
40 |
41 |
42 | depend .depend dep:
43 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
44 |
45 | ifeq (.depend,$(wildcard .depend))
46 | include .depend
47 | endif
48 |
--------------------------------------------------------------------------------
/scullp/mmap.c:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * mmap.c -- memory mapping for the scullp char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: _mmap.c.in,v 1.13 2004/10/18 18:07:36 corbet Exp $
16 | */
17 |
18 | #include
19 |
20 | #include /* everything */
21 | #include /* error codes */
22 | #include
23 | #include
24 | #include
25 | #include "scullp.h" /* local definitions */
26 |
27 |
28 | /*
29 | * open and close: just keep track of how many times the device is
30 | * mapped, to avoid releasing it.
31 | */
32 |
33 | void scullp_vma_open(struct vm_area_struct *vma)
34 | {
35 | struct scullp_dev *dev = vma->vm_private_data;
36 |
37 | dev->vmas++;
38 | }
39 |
40 | void scullp_vma_close(struct vm_area_struct *vma)
41 | {
42 | struct scullp_dev *dev = vma->vm_private_data;
43 |
44 | dev->vmas--;
45 | }
46 |
47 | /*
48 | * The nopage method: the core of the file. It retrieves the
49 | * page required from the scullp device and returns it to the
50 | * user. The count for the page must be incremented, because
51 | * it is automatically decremented at page unmap.
52 | *
53 | * For this reason, "order" must be zero. Otherwise, only the first
54 | * page has its count incremented, and the allocating module must
55 | * release it as a whole block. Therefore, it isn't possible to map
56 | * pages from a multipage block: when they are unmapped, their count
57 | * is individually decreased, and would drop to 0.
58 | */
59 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
60 | typedef int vm_fault_t;
61 | #endif
62 | static vm_fault_t scullp_vma_nopage(struct vm_fault *vmf)
63 | {
64 | unsigned long offset;
65 | struct vm_area_struct *vma = vmf->vma;
66 | struct scullp_dev *ptr, *dev = vma->vm_private_data;
67 | struct page *page = NULL;
68 | void *pageptr = NULL; /* default to "missing" */
69 | vm_fault_t retval = VM_FAULT_NOPAGE;
70 |
71 | mutex_lock(&dev->mutex);
72 | offset = (unsigned long)(vmf->address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
73 | if (offset >= dev->size) goto out; /* out of range */
74 |
75 | /*
76 | * Now retrieve the scullp device from the list,then the page.
77 | * If the device has holes, the process receives a SIGBUS when
78 | * accessing the hole.
79 | */
80 | offset >>= PAGE_SHIFT; /* offset is a number of pages */
81 | for (ptr = dev; ptr && offset >= dev->qset;) {
82 | ptr = ptr->next;
83 | offset -= dev->qset;
84 | }
85 | if (ptr && ptr->data) pageptr = ptr->data[offset];
86 | if (!pageptr) goto out; /* hole or end-of-file */
87 | page = virt_to_page(pageptr);
88 |
89 | /* got it, now increment the count */
90 | get_page(page);
91 | vmf->page = page;
92 | retval = 0;
93 |
94 | out:
95 | mutex_unlock(&dev->mutex);
96 | return retval;
97 | }
98 |
99 |
100 |
101 | struct vm_operations_struct scullp_vm_ops = {
102 | .open = scullp_vma_open,
103 | .close = scullp_vma_close,
104 | .fault = scullp_vma_nopage,
105 | };
106 |
107 |
108 | int scullp_mmap(struct file *filp, struct vm_area_struct *vma)
109 | {
110 | struct inode *inode = filp->f_path.dentry->d_inode;
111 |
112 | /* refuse to map if order is not 0 */
113 | if (scullp_devices[iminor(inode)].order)
114 | return -ENODEV;
115 |
116 | /* don't do anything here: "nopage" will set up page table entries */
117 | vma->vm_ops = &scullp_vm_ops;
118 | vma->vm_private_data = filp->private_data;
119 | scullp_vma_open(vma);
120 | return 0;
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/scullp/scull-shared/scull-async.c:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.c
--------------------------------------------------------------------------------
/scullp/scull-shared/scull-async.h:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.h
--------------------------------------------------------------------------------
/scullp/scullp.h:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * scullp.h -- definitions for the scullp char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | */
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | /*
21 | * Macros to help debugging
22 | */
23 |
24 | #undef PDEBUG /* undef it, just in case */
25 | #ifdef SCULLP_DEBUG
26 | # ifdef __KERNEL__
27 | /* This one if debugging is on, and kernel space */
28 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullp: " fmt, ## args)
29 | # else
30 | /* This one for user space */
31 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
32 | # endif
33 | #else
34 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
35 | #endif
36 |
37 | #undef PDEBUGG
38 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
39 |
40 | #define SCULLP_MAJOR 0 /* dynamic major by default */
41 |
42 | #define SCULLP_DEVS 4 /* scullp0 through scullp3 */
43 |
44 | /*
45 | * The bare device is a variable-length region of memory.
46 | * Use a linked list of indirect blocks.
47 | *
48 | * "scullp_dev->data" points to an array of pointers, each
49 | * pointer refers to a memory page.
50 | *
51 | * The array (quantum-set) is SCULLP_QSET long.
52 | */
53 | #define SCULLP_ORDER 0 /* one page at a time */
54 | #define SCULLP_QSET 500
55 |
56 | struct scullp_dev {
57 | void **data;
58 | struct scullp_dev *next; /* next listitem */
59 | int vmas; /* active mappings */
60 | int order; /* the current allocation order */
61 | int qset; /* the current array size */
62 | size_t size; /* 32-bit will suffice */
63 | struct mutex mutex; /* Mutual exclusion */
64 | struct cdev cdev;
65 | };
66 |
67 | extern struct scullp_dev *scullp_devices;
68 |
69 | extern struct file_operations scullp_fops;
70 |
71 | /*
72 | * The different configurable parameters
73 | */
74 | extern int scullp_major; /* main.c */
75 | extern int scullp_devs;
76 | extern int scullp_order;
77 | extern int scullp_qset;
78 |
79 | /*
80 | * Prototypes for shared functions
81 | */
82 | int scullp_trim(struct scullp_dev *dev);
83 | struct scullp_dev *scullp_follow(struct scullp_dev *dev, int n);
84 |
85 |
86 | #ifdef SCULLP_DEBUG
87 | # define SCULLP_USE_PROC
88 | #endif
89 |
90 | /*
91 | * Ioctl definitions
92 | */
93 |
94 | /* Use 'K' as magic number */
95 | #define SCULLP_IOC_MAGIC 'K'
96 |
97 | #define SCULLP_IOCRESET _IO(SCULLP_IOC_MAGIC, 0)
98 |
99 | /*
100 | * S means "Set" through a ptr,
101 | * T means "Tell" directly
102 | * G means "Get" (to a pointed var)
103 | * Q means "Query", response is on the return value
104 | * X means "eXchange": G and S atomically
105 | * H means "sHift": T and Q atomically
106 | */
107 | #define SCULLP_IOCSORDER _IOW(SCULLP_IOC_MAGIC, 1, int)
108 | #define SCULLP_IOCTORDER _IO(SCULLP_IOC_MAGIC, 2)
109 | #define SCULLP_IOCGORDER _IOR(SCULLP_IOC_MAGIC, 3, int)
110 | #define SCULLP_IOCQORDER _IO(SCULLP_IOC_MAGIC, 4)
111 | #define SCULLP_IOCXORDER _IOWR(SCULLP_IOC_MAGIC, 5, int)
112 | #define SCULLP_IOCHORDER _IO(SCULLP_IOC_MAGIC, 6)
113 | #define SCULLP_IOCSQSET _IOW(SCULLP_IOC_MAGIC, 7, int)
114 | #define SCULLP_IOCTQSET _IO(SCULLP_IOC_MAGIC, 8)
115 | #define SCULLP_IOCGQSET _IOR(SCULLP_IOC_MAGIC, 9, int)
116 | #define SCULLP_IOCQQSET _IO(SCULLP_IOC_MAGIC, 10)
117 | #define SCULLP_IOCXQSET _IOWR(SCULLP_IOC_MAGIC,11, int)
118 | #define SCULLP_IOCHQSET _IO(SCULLP_IOC_MAGIC, 12)
119 |
120 | #define SCULLP_IOC_MAXNR 12
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/scullp/scullp_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scullp"
3 | device="scullp"
4 | mode="664"
5 |
6 | # Group: since distributions do it differently, look for wheel or use staff
7 | if grep '^staff:' /etc/group > /dev/null; then
8 | group="staff"
9 | else
10 | group="wheel"
11 | fi
12 |
13 | # remove stale nodes
14 | rm -f /dev/${device}?
15 |
16 | # invoke insmod with all arguments we got
17 | # and use a pathname, as newer modutils don't look in . by default
18 | insmod ./$module.ko $* || exit 1
19 |
20 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
21 |
22 | mknod /dev/${device}0 c $major 0
23 | mknod /dev/${device}1 c $major 1
24 | mknod /dev/${device}2 c $major 2
25 | mknod /dev/${device}3 c $major 3
26 | ln -sf ${device}0 /dev/${device}
27 |
28 | # give appropriate group/permissions
29 | chgrp $group /dev/${device}[0-3]
30 | chmod $mode /dev/${device}[0-3]
31 |
--------------------------------------------------------------------------------
/scullp/scullp_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scullp"
3 | device="scullp"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # remove nodes
9 | rm -f /dev/${device}[0-3] /dev/${device}
10 |
11 | exit 0
12 |
--------------------------------------------------------------------------------
/scullv/Makefile:
--------------------------------------------------------------------------------
1 |
2 | # Comment/uncomment the following line to enable/disable debugging
3 | #DEBUG = y
4 |
5 |
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSCULLV_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | LDDINC=$(PWD)/../include
13 | EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINC)
14 |
15 | TARGET = scullv
16 |
17 | ifneq ($(KERNELRELEASE),)
18 |
19 | scullv-objs := main.o mmap.o scull-shared/scull-async.o
20 |
21 | obj-m := scullv.o
22 |
23 | else
24 |
25 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
26 | PWD := $(shell pwd)
27 |
28 | modules:
29 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
30 |
31 | endif
32 |
33 |
34 | install:
35 | install -d $(INSTALLDIR)
36 | install -c $(TARGET).o $(INSTALLDIR)
37 |
38 | clean:
39 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers scull-shared/scull-async.o
40 |
41 |
42 | depend .depend dep:
43 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
44 |
45 | ifeq (.depend,$(wildcard .depend))
46 | include .depend
47 | endif
48 |
--------------------------------------------------------------------------------
/scullv/mmap.c:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * mmap.c -- memory mapping for the scullv char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: _mmap.c.in,v 1.13 2004/10/18 18:07:36 corbet Exp $
16 | */
17 |
18 | #include
19 |
20 | #include /* everything */
21 | #include /* error codes */
22 | #include
23 | #include
24 | #include
25 |
26 | #include "scullv.h" /* local definitions */
27 |
28 |
29 | /*
30 | * open and close: just keep track of how many times the device is
31 | * mapped, to avoid releasing it.
32 | */
33 |
34 | void scullv_vma_open(struct vm_area_struct *vma)
35 | {
36 | struct scullv_dev *dev = vma->vm_private_data;
37 |
38 | dev->vmas++;
39 | }
40 |
41 | void scullv_vma_close(struct vm_area_struct *vma)
42 | {
43 | struct scullv_dev *dev = vma->vm_private_data;
44 |
45 | dev->vmas--;
46 | }
47 |
48 | /*
49 | * The nopage method: the core of the file. It retrieves the
50 | * page required from the scullv device and returns it to the
51 | * user. The count for the page must be incremented, because
52 | * it is automatically decremented at page unmap.
53 | *
54 | * For this reason, "order" must be zero. Otherwise, only the first
55 | * page has its count incremented, and the allocating module must
56 | * release it as a whole block. Therefore, it isn't possible to map
57 | * pages from a multipage block: when they are unmapped, their count
58 | * is individually decreased, and would drop to 0.
59 | */
60 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
61 | typedef int vm_fault_t;
62 | #endif
63 |
64 | static vm_fault_t scullv_vma_nopage(struct vm_fault *vmf)
65 | {
66 | unsigned long offset;
67 | struct vm_area_struct *vma = vmf->vma;
68 | struct scullv_dev *ptr, *dev = vma->vm_private_data;
69 | struct page *page = NULL;
70 | void *pageptr = NULL; /* default to "missing" */
71 | vm_fault_t retval = VM_FAULT_NOPAGE;
72 |
73 | mutex_lock(&dev->mutex);
74 | offset = (unsigned long)(vmf->address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
75 | if (offset >= dev->size) goto out; /* out of range */
76 |
77 | /*
78 | * Now retrieve the scullv device from the list,then the page.
79 | * If the device has holes, the process receives a SIGBUS when
80 | * accessing the hole.
81 | */
82 | offset >>= PAGE_SHIFT; /* offset is a number of pages */
83 | for (ptr = dev; ptr && offset >= dev->qset;) {
84 | ptr = ptr->next;
85 | offset -= dev->qset;
86 | }
87 | if (ptr && ptr->data) pageptr = ptr->data[offset];
88 | if (!pageptr) goto out; /* hole or end-of-file */
89 |
90 | /*
91 | * After scullv lookup, "page" is now the address of the page
92 | * needed by the current process. Since it's a vmalloc address,
93 | * turn it into a struct page.
94 | */
95 | page = vmalloc_to_page(pageptr);
96 |
97 | /* got it, now increment the count */
98 | get_page(page);
99 | vmf->page = page;
100 | retval = 0;
101 |
102 | out:
103 | mutex_unlock(&dev->mutex);
104 | return retval;
105 | }
106 |
107 |
108 |
109 | struct vm_operations_struct scullv_vm_ops = {
110 | .open = scullv_vma_open,
111 | .close = scullv_vma_close,
112 | .fault = scullv_vma_nopage,
113 | };
114 |
115 |
116 | int scullv_mmap(struct file *filp, struct vm_area_struct *vma)
117 | {
118 |
119 | /* don't do anything here: "nopage" will set up page table entries */
120 | vma->vm_ops = &scullv_vm_ops;
121 | vma->vm_private_data = filp->private_data;
122 | scullv_vma_open(vma);
123 | return 0;
124 | }
125 |
126 |
--------------------------------------------------------------------------------
/scullv/scull-shared/scull-async.c:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.c
--------------------------------------------------------------------------------
/scullv/scull-shared/scull-async.h:
--------------------------------------------------------------------------------
1 | ../../scull-shared/scull-async.h
--------------------------------------------------------------------------------
/scullv/scullv.h:
--------------------------------------------------------------------------------
1 | /* -*- C -*-
2 | * scullv.h -- definitions for the scullv char module
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | */
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | /*
21 | * Macros to help debugging
22 | */
23 |
24 | #undef PDEBUG /* undef it, just in case */
25 | #ifdef SCULLV_DEBUG
26 | # ifdef __KERNEL__
27 | /* This one if debugging is on, and kernel space */
28 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullv: " fmt, ## args)
29 | # else
30 | /* This one for user space */
31 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
32 | # endif
33 | #else
34 | # define PDEBUG(fmt, args...) /* not debugging: nothing */
35 | #endif
36 |
37 | #undef PDEBUGG
38 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
39 |
40 | #define SCULLV_MAJOR 0 /* dynamic major by default */
41 |
42 | #define SCULLV_DEVS 4 /* scullv0 through scullv3 */
43 |
44 | /*
45 | * The bare device is a variable-length region of memory.
46 | * Use a linked list of indirect blocks.
47 | *
48 | * "scullv_dev->data" points to an array of pointers, each
49 | * pointer refers to a memory page.
50 | *
51 | * The array (quantum-set) is SCULLV_QSET long.
52 | */
53 | #define SCULLV_ORDER 4 /* 16 pages at a time */
54 | #define SCULLV_QSET 500
55 |
56 | struct scullv_dev {
57 | void **data;
58 | struct scullv_dev *next; /* next listitem */
59 | int vmas; /* active mappings */
60 | int order; /* the current allocation order */
61 | int qset; /* the current array size */
62 | size_t size; /* 32-bit will suffice */
63 | struct mutex mutex; /* Mutual exclusion */
64 | struct cdev cdev;
65 | };
66 |
67 | extern struct scullv_dev *scullv_devices;
68 |
69 | extern struct file_operations scullv_fops;
70 |
71 | /*
72 | * The different configurable parameters
73 | */
74 | extern int scullv_major; /* main.c */
75 | extern int scullv_devs;
76 | extern int scullv_order;
77 | extern int scullv_qset;
78 |
79 | /*
80 | * Prototypes for shared functions
81 | */
82 | int scullv_trim(struct scullv_dev *dev);
83 | struct scullv_dev *scullv_follow(struct scullv_dev *dev, int n);
84 |
85 |
86 | #ifdef SCULLV_DEBUG
87 | # define SCULLV_USE_PROC
88 | #endif
89 |
90 | /*
91 | * Ioctl definitions
92 | */
93 |
94 | /* Use 'K' as magic number */
95 | #define SCULLV_IOC_MAGIC 'K'
96 |
97 | #define SCULLV_IOCRESET _IO(SCULLV_IOC_MAGIC, 0)
98 |
99 | /*
100 | * S means "Set" through a ptr,
101 | * T means "Tell" directly
102 | * G means "Get" (to a pointed var)
103 | * Q means "Query", response is on the return value
104 | * X means "eXchange": G and S atomically
105 | * H means "sHift": T and Q atomically
106 | */
107 | #define SCULLV_IOCSORDER _IOW(SCULLV_IOC_MAGIC, 1, int)
108 | #define SCULLV_IOCTORDER _IO(SCULLV_IOC_MAGIC, 2)
109 | #define SCULLV_IOCGORDER _IOR(SCULLV_IOC_MAGIC, 3, int)
110 | #define SCULLV_IOCQORDER _IO(SCULLV_IOC_MAGIC, 4)
111 | #define SCULLV_IOCXORDER _IOWR(SCULLV_IOC_MAGIC, 5, int)
112 | #define SCULLV_IOCHORDER _IO(SCULLV_IOC_MAGIC, 6)
113 | #define SCULLV_IOCSQSET _IOW(SCULLV_IOC_MAGIC, 7, int)
114 | #define SCULLV_IOCTQSET _IO(SCULLV_IOC_MAGIC, 8)
115 | #define SCULLV_IOCGQSET _IOR(SCULLV_IOC_MAGIC, 9, int)
116 | #define SCULLV_IOCQQSET _IO(SCULLV_IOC_MAGIC, 10)
117 | #define SCULLV_IOCXQSET _IOWR(SCULLV_IOC_MAGIC,11, int)
118 | #define SCULLV_IOCHQSET _IO(SCULLV_IOC_MAGIC, 12)
119 |
120 | #define SCULLV_IOC_MAXNR 12
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/scullv/scullv_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scullv"
3 | device="scullv"
4 | mode="664"
5 |
6 | # Group: since distributions do it differently, look for wheel or use staff
7 | if grep '^staff:' /etc/group > /dev/null; then
8 | group="staff"
9 | else
10 | group="wheel"
11 | fi
12 |
13 | # remove stale nodes
14 | rm -f /dev/${device}?
15 |
16 | # invoke insmod with all arguments we got
17 | # and use a pathname, as newer modutils don't look in . by default
18 | insmod ./$module.ko $* || exit 1
19 |
20 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
21 |
22 | mknod /dev/${device}0 c $major 0
23 | mknod /dev/${device}1 c $major 1
24 | mknod /dev/${device}2 c $major 2
25 | mknod /dev/${device}3 c $major 3
26 | ln -sf ${device}0 /dev/${device}
27 |
28 | # give appropriate group/permissions
29 | chgrp $group /dev/${device}[0-3]
30 | chmod $mode /dev/${device}[0-3]
31 |
--------------------------------------------------------------------------------
/scullv/scullv_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="scullv"
3 | device="scullv"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # remove nodes
9 | rm -f /dev/${device}[0-3] /dev/${device}
10 |
11 | exit 0
12 |
--------------------------------------------------------------------------------
/short/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 |
5 | # Add your debugging flag (or not) to CFLAGS
6 | ifeq ($(DEBUG),y)
7 | DEBFLAGS = -O -g -DSHORT_DEBUG # "-O" is needed to expand inlines
8 | else
9 | DEBFLAGS = -O2
10 | endif
11 |
12 | EXTRA_CFLAGS += $(DEBFLAGS)
13 | EXTRA_CFLAGS += -I..
14 |
15 | ifneq ($(KERNELRELEASE),)
16 | # call from kernel build system
17 |
18 | obj-m := short.o
19 |
20 | else
21 |
22 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
23 | PWD := $(shell pwd)
24 |
25 | default:
26 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
27 |
28 | endif
29 |
30 |
31 | clean:
32 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
33 |
34 | depend .depend dep:
35 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
36 |
37 |
38 | ifeq (.depend,$(wildcard .depend))
39 | include .depend
40 | endif
41 |
--------------------------------------------------------------------------------
/short/short_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="short"
3 | device="short"
4 | mode="664"
5 |
6 | # Group: since distributions do it differently, look for wheel or use staff
7 | if grep '^staff:' /etc/group > /dev/null; then
8 | group="staff"
9 | else
10 | group="wheel"
11 | fi
12 |
13 |
14 | # invoke insmod with all arguments we got
15 | # and use a pathname, as newer modutils don't look in . by default
16 | insmod ./$module.ko $* || exit 1
17 |
18 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
19 |
20 | # Create 8 entry points, as SHORT_NR_PORTS is 8 by default
21 | rm -f /dev/${device}[0-7]
22 | mknod /dev/${device}0 c $major 0
23 | mknod /dev/${device}1 c $major 1
24 | mknod /dev/${device}2 c $major 2
25 | mknod /dev/${device}3 c $major 3
26 | mknod /dev/${device}4 c $major 4
27 | mknod /dev/${device}5 c $major 5
28 | mknod /dev/${device}6 c $major 6
29 | mknod /dev/${device}7 c $major 7
30 |
31 | rm -f /dev/${device}[0-3][ps]
32 | mknod /dev/${device}0p c $major 16
33 | mknod /dev/${device}1p c $major 17
34 | mknod /dev/${device}2p c $major 18
35 | mknod /dev/${device}3p c $major 19
36 | mknod /dev/${device}4p c $major 20
37 | mknod /dev/${device}5p c $major 21
38 | mknod /dev/${device}6p c $major 22
39 | mknod /dev/${device}7p c $major 23
40 |
41 | mknod /dev/${device}0s c $major 32
42 | mknod /dev/${device}1s c $major 33
43 | mknod /dev/${device}2s c $major 34
44 | mknod /dev/${device}3s c $major 35
45 | mknod /dev/${device}4s c $major 36
46 | mknod /dev/${device}5s c $major 37
47 | mknod /dev/${device}6s c $major 38
48 | mknod /dev/${device}7s c $major 39
49 |
50 | rm -f /dev/${device}int /dev/${device}print
51 | mknod /dev/${device}int c $major 128
52 | mknod /dev/${device}print c $major 129
53 |
54 | chgrp $group /dev/${device}[0-7] /dev/${device}[0-7][ps] /dev/${device}int
55 | chmod $mode /dev/${device}[0-7] /dev/${device}[0-7][ps] /dev/${device}int
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/short/short_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="short"
3 | device="short"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # Remove stale nodes
9 |
10 | rm -f /dev/${device}[0-7] /dev/${device}[0-7][ps] \
11 | /dev/${device}int /dev/${device}print
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/shortprint/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 | EXTRA_CFLAGS += -O2 -I..
5 |
6 | ifneq ($(KERNELRELEASE),)
7 | # call from kernel build system
8 |
9 | obj-m := shortprint.o
10 |
11 | else
12 |
13 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
14 | PWD := $(shell pwd)
15 |
16 | default:
17 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
18 |
19 | endif
20 |
21 |
22 | clean:
23 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
24 |
25 | depend .depend dep:
26 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
27 |
28 |
29 | ifeq (.depend,$(wildcard .depend))
30 | include .depend
31 | endif
32 |
--------------------------------------------------------------------------------
/shortprint/shortprint.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Useful info describing the parallel port device.
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | */
16 |
17 | /*
18 | * Register offsets
19 | */
20 | #define SP_DATA 0x00
21 | #define SP_STATUS 0x01
22 | #define SP_CONTROL 0x02
23 | #define SP_NPORTS 3
24 |
25 | /*
26 | * Status register bits.
27 | */
28 | #define SP_SR_BUSY 0x80
29 | #define SP_SR_ACK 0x40
30 | #define SP_SR_PAPER 0x20
31 | #define SP_SR_ONLINE 0x10
32 | #define SP_SR_ERR 0x08
33 |
34 | /*
35 | * Control register.
36 | */
37 | #define SP_CR_IRQ 0x10
38 | #define SP_CR_SELECT 0x08
39 | #define SP_CR_INIT 0x04
40 | #define SP_CR_AUTOLF 0x02
41 | #define SP_CR_STROBE 0x01
42 |
43 | /*
44 | * Minimum space before waking up a writer.
45 | */
46 | #define SP_MIN_SPACE PAGE_SIZE/2
47 |
--------------------------------------------------------------------------------
/shortprint/shortprint_load:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="shortprint"
3 | device="shortprint"
4 | mode="666"
5 |
6 | # Group: since distributions do it differently, look for wheel or use staff
7 | if grep '^staff:' /etc/group > /dev/null; then
8 | group="staff"
9 | else
10 | group="wheel"
11 | fi
12 |
13 |
14 | # invoke insmod with all arguments we got
15 | # and use a pathname, as newer modutils don't look in . by default
16 | insmod ./$module.ko $* || exit 1
17 |
18 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
19 |
20 | # Create 8 entry points, as SHORT_NR_PORTS is 8 by default
21 | rm -f /dev/${device}
22 | mknod /dev/${device} c $major 0
23 |
24 | chgrp $group /dev/${device}
25 | chmod $mode /dev/${device}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/shortprint/shortprint_unload:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | module="shortprint"
3 | device="shortprint"
4 |
5 | # invoke rmmod with all arguments we got
6 | rmmod $module $* || exit 1
7 |
8 | # Remove stale nodes
9 | rm -f /dev/${device}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/simple/Makefile:
--------------------------------------------------------------------------------
1 | # Comment/uncomment the following line to disable/enable debugging
2 | #DEBUG = y
3 |
4 | # Add your debugging flag (or not) to CFLAGS
5 | ifeq ($(DEBUG),y)
6 | DEBFLAGS = -O -g # "-O" is needed to expand inlines
7 | else
8 | DEBFLAGS = -O2
9 | endif
10 |
11 | EXTRA_CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR)
12 |
13 | ifneq ($(KERNELRELEASE),)
14 | # call from kernel build system
15 |
16 | obj-m := simple.o
17 |
18 | else
19 |
20 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build
21 | PWD := $(shell pwd)
22 |
23 | default:
24 | $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINCDIR=$(PWD)/../include modules
25 |
26 | endif
27 |
28 |
29 |
30 | clean:
31 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers
32 |
33 | depend .depend dep:
34 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend
35 |
36 |
37 | ifeq (.depend,$(wildcard .depend))
38 | include .depend
39 | endif
40 |
--------------------------------------------------------------------------------
/simple/simple.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple - REALLY simple memory mapping demonstration.
3 | *
4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 | * Copyright (C) 2001 O'Reilly & Associates
6 | *
7 | * The source code in this file can be freely used, adapted,
8 | * and redistributed in source or binary form, so long as an
9 | * acknowledgment appears in derived source files. The citation
10 | * should list that the code comes from the book "Linux Device
11 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 | * by O'Reilly & Associates. No warranty is attached;
13 | * we cannot take responsibility for errors or fitness for use.
14 | *
15 | * $Id: simple.c,v 1.12 2005/01/31 16:15:31 rubini Exp $
16 | */
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #include /* printk() */
23 | #include /* kmalloc() */
24 | #include /* everything... */
25 | #include /* error codes */
26 | #include /* size_t */
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include