├── LICENSE ├── Makefile ├── include └── lddbus.h ├── lddbus ├── Makefile └── lddbus.c ├── misc-modules ├── Makefile ├── complete.c ├── faulty.c ├── hello.c ├── hellop.c ├── jiq.c ├── jit.c ├── kdataalign.c ├── kdatasize.c ├── 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 ├── pci ├── Makefile └── pci_skel.c ├── sbull ├── Makefile ├── sbull.c ├── sbull.h ├── sbull_load └── sbull_unload ├── scull ├── Makefile ├── access.c ├── main.c ├── pipe.c ├── scull.h ├── scull.init ├── scull_load └── scull_unload ├── scullc ├── Makefile ├── main.c ├── mmap.c ├── scullc.h ├── scullc_load └── scullc_unload ├── sculld ├── Makefile ├── main.c ├── mmap.c ├── sculld.h ├── sculld_load └── sculld_unload ├── scullp ├── Makefile ├── main.c ├── mmap.c ├── scullp.h ├── scullp_load └── scullp_unload ├── scullv ├── Makefile ├── main.c ├── mmap.c ├── 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 /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 sculld scullp scullv sbull snull\ 4 | short shortprint pci simple usb tty lddbus 5 | 6 | all: subdirs 7 | 8 | subdirs: 9 | for n in $(SUBDIRS); do $(MAKE) -C $$n || exit 1; done 10 | 11 | clean: 12 | for n in $(SUBDIRS); do $(MAKE) -C $$n clean; done 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lddbus/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to disable/enable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -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) SUBDIRS=$(PWD) LDDINCDIR=$(PWD)/../include modules 26 | 27 | endif 28 | 29 | 30 | 31 | clean: 32 | rm -rf *.o *.ko *~ core .depend *.mod.c .*.cmd .tmp_versions .*.o.d 33 | 34 | depend .depend dep: 35 | $(CC) -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 "lddbus.h" 25 | 26 | MODULE_AUTHOR("Jonathan Corbet"); 27 | MODULE_LICENSE("Dual BSD/GPL"); 28 | static char *Version = "$Revision: 1.9 $"; 29 | 30 | /* 31 | * Respond to hotplug events. 32 | */ 33 | static int ldd_uevent(struct device *dev, struct kobj_uevent_env *env) 34 | { 35 | return add_uevent_var(env, "LDDBUS_VERSION=%s", Version); 36 | } 37 | 38 | /* 39 | * Match LDD devices to drivers. Just do a simple name test. 40 | */ 41 | static int ldd_match(struct device *dev, struct device_driver *driver) 42 | { 43 | return !strncmp(dev_name(dev), driver->name, strlen(driver->name)); 44 | } 45 | 46 | 47 | /* 48 | * The LDD bus device. 49 | */ 50 | static void ldd_bus_release(struct device *dev) 51 | { 52 | printk(KERN_DEBUG "lddbus release\n"); 53 | } 54 | 55 | struct device ldd_bus = { 56 | .init_name = "ldd0", 57 | .release = ldd_bus_release 58 | }; 59 | 60 | 61 | /* 62 | * And the bus type. 63 | */ 64 | struct bus_type ldd_bus_type = { 65 | .name = "ldd", 66 | .match = ldd_match, 67 | .uevent = ldd_uevent, 68 | }; 69 | 70 | /* 71 | * Export a simple attribute. 72 | */ 73 | static ssize_t show_bus_version(struct bus_type *bus, char *buf) 74 | { 75 | return snprintf(buf, PAGE_SIZE, "%s\n", Version); 76 | } 77 | 78 | static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); 79 | 80 | 81 | 82 | /* 83 | * LDD devices. 84 | */ 85 | 86 | /* 87 | * For now, no references to LDDbus devices go out which are not 88 | * tracked via the module reference count, so we use a no-op 89 | * release function. 90 | */ 91 | static void ldd_dev_release(struct device *dev) 92 | { } 93 | 94 | int register_ldd_device(struct ldd_device *ldddev) 95 | { 96 | ldddev->dev.bus = &ldd_bus_type; 97 | ldddev->dev.parent = &ldd_bus; 98 | ldddev->dev.release = ldd_dev_release; 99 | dev_set_name(&ldddev->dev, "%s", ldddev->name); 100 | return device_register(&ldddev->dev); 101 | } 102 | EXPORT_SYMBOL(register_ldd_device); 103 | 104 | void unregister_ldd_device(struct ldd_device *ldddev) 105 | { 106 | device_unregister(&ldddev->dev); 107 | } 108 | EXPORT_SYMBOL(unregister_ldd_device); 109 | 110 | /* 111 | * Crude driver interface. 112 | */ 113 | 114 | 115 | static ssize_t show_version(struct device_driver *driver, char *buf) 116 | { 117 | struct ldd_driver *ldriver = to_ldd_driver(driver); 118 | 119 | sprintf(buf, "%s\n", ldriver->version); 120 | return strlen(buf); 121 | } 122 | 123 | 124 | int register_ldd_driver(struct ldd_driver *driver) 125 | { 126 | int ret; 127 | 128 | driver->driver.bus = &ldd_bus_type; 129 | ret = driver_register(&driver->driver); 130 | if (ret) 131 | return ret; 132 | driver->version_attr.attr.name = "version"; 133 | driver->version_attr.attr.mode = S_IRUGO; 134 | driver->version_attr.show = show_version; 135 | driver->version_attr.store = NULL; 136 | return driver_create_file(&driver->driver, &driver->version_attr); 137 | } 138 | 139 | void unregister_ldd_driver(struct ldd_driver *driver) 140 | { 141 | driver_unregister(&driver->driver); 142 | } 143 | EXPORT_SYMBOL(register_ldd_driver); 144 | EXPORT_SYMBOL(unregister_ldd_driver); 145 | 146 | 147 | 148 | static int __init ldd_bus_init(void) 149 | { 150 | int ret; 151 | 152 | ret = bus_register(&ldd_bus_type); 153 | if (ret) 154 | return ret; 155 | if (bus_create_file(&ldd_bus_type, &bus_attr_version)) 156 | printk(KERN_NOTICE "Unable to create version attribute\n"); 157 | ret = device_register(&ldd_bus); 158 | if (ret) 159 | printk(KERN_NOTICE "Unable to register ldd0\n"); 160 | return ret; 161 | } 162 | 163 | static void ldd_bus_exit(void) 164 | { 165 | device_unregister(&ldd_bus); 166 | bus_unregister(&ldd_bus_type); 167 | } 168 | 169 | module_init(ldd_bus_init); 170 | module_exit(ldd_bus_exit); 171 | -------------------------------------------------------------------------------- /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 | ifeq ($(KERNELRELEASE),) 8 | 9 | # Assume the source tree is where the running kernel was built 10 | # You should set KERNELDIR in the environment if it's elsewhere 11 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 12 | # The current directory is passed to sub-makes as argument 13 | PWD := $(shell pwd) 14 | 15 | modules: 16 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 17 | 18 | modules_install: 19 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 20 | 21 | clean: 22 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 23 | 24 | .PHONY: modules modules_install clean 25 | 26 | else 27 | # called from kernel build system: just declare what our modules are 28 | obj-m := hello.o hellop.o seq.o jit.o jiq.o sleepy.o complete.o \ 29 | silly.o faulty.o kdatasize.o kdataalign.o 30 | endif 31 | 32 | 33 | -------------------------------------------------------------------------------- /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 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | MODULE_LICENSE("Dual BSD/GPL"); 28 | 29 | static int complete_major = 0; 30 | static int complete_minor = 0; 31 | 32 | DECLARE_COMPLETION(comp); 33 | 34 | ssize_t complete_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_for_completion(&comp); 39 | printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); 40 | return 0; /* EOF */ 41 | } 42 | 43 | ssize_t complete_write(struct file *filp, const char __user *buf, size_t count, 44 | loff_t *pos) 45 | { 46 | printk(KERN_DEBUG "process %i (%s) awakening the readers...\n", 47 | current->pid, current->comm); 48 | complete(&comp); 49 | return count; 50 | } 51 | 52 | 53 | struct file_operations complete_fops = { 54 | .owner = THIS_MODULE, 55 | .read = complete_read, 56 | .write = complete_write, 57 | }; 58 | 59 | 60 | static int __init complete_init(void) 61 | { 62 | int result; 63 | dev_t dev; 64 | struct cdev *complete_cdev; 65 | 66 | /* Register dynamically. */ 67 | result = alloc_chrdev_region(&dev, complete_minor, 1, "complete"); 68 | 69 | if (result < 0) { 70 | printk(KERN_WARNING "complete: couldn't get major number assignment\n"); 71 | return result; 72 | } 73 | 74 | complete_major = MAJOR(dev); 75 | 76 | complete_cdev = cdev_alloc(); 77 | complete_cdev->ops = &complete_fops; 78 | cdev_add(complete_cdev, dev, 1); 79 | 80 | return 0; 81 | } 82 | 83 | static void __exit complete_cleanup(void) 84 | { 85 | dev_t dev = MKDEV(complete_major, complete_minor); 86 | unregister_chrdev_region(dev, 1); 87 | } 88 | 89 | module_init(complete_init); 90 | module_exit(complete_cleanup); 91 | 92 | -------------------------------------------------------------------------------- /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 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | MODULE_LICENSE("Dual BSD/GPL"); 27 | 28 | int faulty_major = 0; 29 | int faulty_minor = 0; 30 | 31 | ssize_t faulty_read(struct file *filp, char __user *buf, 32 | size_t count, loff_t *pos) 33 | { 34 | int ret; 35 | char stack_buf[4]; 36 | 37 | /* Let's try a buffer overflow. */ 38 | memset(stack_buf, 0xff, 20); 39 | if (count > 4) 40 | count = 4; /* Copy 4 bytes to the user. */ 41 | ret = copy_to_user(buf, stack_buf, count); 42 | if (!ret) 43 | return count; 44 | return ret; 45 | } 46 | 47 | ssize_t faulty_write(struct file *filp, const char __user *buf, size_t count, 48 | loff_t *pos) 49 | { 50 | /* Make a simple fault by dereferencing a NULL pointer. */ 51 | *(int *)0 = 0; 52 | return 0; 53 | } 54 | 55 | 56 | struct file_operations faulty_fops = { 57 | .read = faulty_read, 58 | .write = faulty_write, 59 | .owner = THIS_MODULE 60 | }; 61 | 62 | 63 | static int __init faulty_init(void) 64 | { 65 | int result; 66 | dev_t dev; 67 | struct cdev *faulty_cdev; 68 | 69 | /* Register dynamically. */ 70 | result = alloc_chrdev_region(&dev, faulty_minor, 1, "faulty"); 71 | 72 | if (result < 0) { 73 | printk(KERN_WARNING "faulty: couldn't get major number assignment\n"); 74 | return result; 75 | } 76 | 77 | faulty_major = MAJOR(dev); 78 | 79 | faulty_cdev = cdev_alloc(); 80 | faulty_cdev->ops = &faulty_fops; 81 | cdev_add(faulty_cdev, dev, 1); 82 | 83 | return 0; 84 | } 85 | 86 | static void __exit faulty_cleanup(void) 87 | { 88 | dev_t dev = MKDEV(faulty_major, faulty_minor); 89 | unregister_chrdev_region(dev, 1); 90 | } 91 | 92 | module_init(faulty_init); 93 | module_exit(faulty_cleanup); 94 | -------------------------------------------------------------------------------- /misc-modules/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | MODULE_LICENSE("Dual BSD/GPL"); 6 | 7 | static int __init hello_init(void) 8 | { 9 | printk(KERN_ALERT "Hello, world\n"); 10 | return 0; 11 | } 12 | 13 | static void __exit hello_exit(void) 14 | { 15 | printk(KERN_ALERT "Goodbye, cruel world\n"); 16 | } 17 | 18 | module_init(hello_init); 19 | module_exit(hello_exit); 20 | -------------------------------------------------------------------------------- /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 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include /* everything... */ 24 | #include 25 | #include /* error codes */ 26 | #include 27 | #include 28 | #include /* tasklets */ 29 | 30 | MODULE_LICENSE("Dual BSD/GPL"); 31 | 32 | /* 33 | * The delay for the delayed workqueue timer file. 34 | */ 35 | static long delay = 1; 36 | module_param(delay, long, 0); 37 | 38 | 39 | /* 40 | * This module is a silly one: it only embeds short code fragments 41 | * that show how enqueued tasks `feel' the environment 42 | */ 43 | 44 | #define LIMIT (PAGE_SIZE-128) /* don't print any more after this size */ 45 | 46 | /* 47 | * Print information about the current environment. This is called from 48 | * within the task queues. If the limit is reched, awake the reading 49 | * process. 50 | */ 51 | static DECLARE_WAIT_QUEUE_HEAD (jiq_wait); 52 | 53 | /* 54 | * Keep track of info we need between task queue runs. 55 | */ 56 | static struct clientdata { 57 | struct work_struct jiq_work; 58 | struct delayed_work jiq_delayed_work; 59 | int len; 60 | char *buf; 61 | unsigned long jiffies; 62 | long delay; 63 | } jiq_data; 64 | 65 | #define SCHEDULER_QUEUE ((task_queue *) 1) 66 | 67 | 68 | 69 | static void jiq_print_tasklet(unsigned long); 70 | static DECLARE_TASKLET(jiq_tasklet, jiq_print_tasklet, (unsigned long)&jiq_data); 71 | 72 | 73 | /* 74 | * Do the printing; return non-zero if the task should be rescheduled. 75 | */ 76 | static int jiq_print(void *ptr) 77 | { 78 | struct clientdata *data = ptr; 79 | int len = data->len; 80 | char *buf = data->buf; 81 | unsigned long j = jiffies; 82 | 83 | if (len > LIMIT) { 84 | wake_up_interruptible(&jiq_wait); 85 | return 0; 86 | } 87 | 88 | if (len == 0) 89 | len = sprintf(buf," time delta preempt pid cpu command\n"); 90 | else 91 | len =0; 92 | 93 | /* intr_count is only exported since 1.3.5, but 1.99.4 is needed anyways */ 94 | len += sprintf(buf+len, "%9li %4li %3i %5i %3i %s\n", 95 | j, j - data->jiffies, 96 | preempt_count(), current->pid, smp_processor_id(), 97 | current->comm); 98 | 99 | data->len += len; 100 | data->buf += len; 101 | data->jiffies = j; 102 | return 1; 103 | } 104 | 105 | 106 | /* 107 | * Call jiq_print from a work queue 108 | */ 109 | static void jiq_print_wq(struct work_struct *work) 110 | { 111 | struct clientdata *data = container_of(work, struct clientdata, jiq_work); 112 | 113 | if (! jiq_print(data)) 114 | return; 115 | 116 | schedule_work(&jiq_data.jiq_work); 117 | } 118 | 119 | static void jiq_print_wq_delayed(struct work_struct *work) 120 | { 121 | struct clientdata *data = container_of(work, struct clientdata, jiq_delayed_work.work); 122 | 123 | if (! jiq_print(data)) 124 | return; 125 | 126 | schedule_delayed_work(&jiq_data.jiq_delayed_work, data->delay); 127 | } 128 | 129 | static int jiq_read_wq(char *buf, char **start, off_t offset, 130 | int len, int *eof, void *data) 131 | { 132 | DEFINE_WAIT(wait); 133 | 134 | jiq_data.len = 0; /* nothing printed, yet */ 135 | jiq_data.buf = buf; /* print in this place */ 136 | jiq_data.jiffies = jiffies; /* initial time */ 137 | jiq_data.delay = 0; 138 | 139 | prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE); 140 | schedule_work(&jiq_data.jiq_work); 141 | schedule(); 142 | finish_wait(&jiq_wait, &wait); 143 | 144 | *eof = 1; 145 | return jiq_data.len; 146 | } 147 | 148 | 149 | static int jiq_read_wq_delayed(char *buf, char **start, off_t offset, 150 | int len, int *eof, void *data) 151 | { 152 | DEFINE_WAIT(wait); 153 | 154 | jiq_data.len = 0; /* nothing printed, yet */ 155 | jiq_data.buf = buf; /* print in this place */ 156 | jiq_data.jiffies = jiffies; /* initial time */ 157 | jiq_data.delay = delay; 158 | 159 | prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE); 160 | schedule_delayed_work(&jiq_data.jiq_delayed_work, delay); 161 | schedule(); 162 | finish_wait(&jiq_wait, &wait); 163 | 164 | *eof = 1; 165 | return jiq_data.len; 166 | } 167 | 168 | 169 | 170 | 171 | /* 172 | * Call jiq_print from a tasklet 173 | */ 174 | static void jiq_print_tasklet(unsigned long ptr) 175 | { 176 | if (jiq_print ((void *) ptr)) 177 | tasklet_schedule (&jiq_tasklet); 178 | } 179 | 180 | 181 | 182 | static int jiq_read_tasklet(char *buf, char **start, off_t offset, int len, 183 | int *eof, void *data) 184 | { 185 | jiq_data.len = 0; /* nothing printed, yet */ 186 | jiq_data.buf = buf; /* print in this place */ 187 | jiq_data.jiffies = jiffies; /* initial time */ 188 | 189 | tasklet_schedule(&jiq_tasklet); 190 | interruptible_sleep_on(&jiq_wait); /* sleep till completion */ 191 | 192 | *eof = 1; 193 | return jiq_data.len; 194 | } 195 | 196 | 197 | 198 | 199 | /* 200 | * This one, instead, tests out the timers. 201 | */ 202 | 203 | static struct timer_list jiq_timer; 204 | 205 | static void jiq_timedout(unsigned long ptr) 206 | { 207 | jiq_print((void *)ptr); /* print a line */ 208 | wake_up_interruptible(&jiq_wait); /* awake the process */ 209 | } 210 | 211 | 212 | static int jiq_read_run_timer(char *buf, char **start, off_t offset, 213 | int len, int *eof, void *data) 214 | { 215 | 216 | jiq_data.len = 0; /* prepare the argument for jiq_print() */ 217 | jiq_data.buf = buf; 218 | jiq_data.jiffies = jiffies; 219 | 220 | init_timer(&jiq_timer); /* init the timer structure */ 221 | jiq_timer.function = jiq_timedout; 222 | jiq_timer.data = (unsigned long)&jiq_data; 223 | jiq_timer.expires = jiffies + HZ; /* one second */ 224 | 225 | jiq_print(&jiq_data); /* print and go to sleep */ 226 | add_timer(&jiq_timer); 227 | interruptible_sleep_on(&jiq_wait); /* RACE */ 228 | del_timer_sync(&jiq_timer); /* in case a signal woke us up */ 229 | 230 | *eof = 1; 231 | return jiq_data.len; 232 | } 233 | 234 | 235 | 236 | /* 237 | * the init/clean material 238 | */ 239 | 240 | static int jiq_init(void) 241 | { 242 | 243 | /* this line is in jiq_init() */ 244 | INIT_WORK(&jiq_data.jiq_work, jiq_print_wq); 245 | INIT_DELAYED_WORK(&jiq_data.jiq_delayed_work, jiq_print_wq_delayed); 246 | 247 | create_proc_read_entry("jiqwq", 0, NULL, jiq_read_wq, NULL); 248 | create_proc_read_entry("jiqwqdelay", 0, NULL, jiq_read_wq_delayed, NULL); 249 | create_proc_read_entry("jiqtimer", 0, NULL, jiq_read_run_timer, NULL); 250 | create_proc_read_entry("jiqtasklet", 0, NULL, jiq_read_tasklet, NULL); 251 | 252 | return 0; /* succeed */ 253 | } 254 | 255 | static void jiq_cleanup(void) 256 | { 257 | remove_proc_entry("jiqwq", NULL); 258 | remove_proc_entry("jiqwqdelay", NULL); 259 | remove_proc_entry("jiqtimer", NULL); 260 | remove_proc_entry("jiqtasklet", NULL); 261 | } 262 | 263 | 264 | module_init(jiq_init); 265 | module_exit(jiq_cleanup); 266 | -------------------------------------------------------------------------------- /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 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | /* 33 | * This module is a silly one: it only embeds short code fragments 34 | * that show how time delays can be handled in the kernel. 35 | */ 36 | 37 | #define JIT_ASYNC_LOOPS 5 38 | 39 | int delay = HZ; /* The default delay, expressed in jiffies. */ 40 | module_param(delay, int, 0); 41 | 42 | int tdelay = 10; 43 | module_param(tdelay, int, 0); 44 | 45 | MODULE_AUTHOR("Alessandro Rubini"); 46 | MODULE_LICENSE("Dual BSD/GPL"); 47 | 48 | /* Use these as data pointers, to implement four files in one function. */ 49 | enum jit_files { 50 | JIT_BUSY, 51 | JIT_SCHED, 52 | JIT_QUEUE, 53 | JIT_SCHEDTO 54 | }; 55 | 56 | /* 57 | * This function prints one line of data, after sleeping one second. 58 | * It can sleep in different ways, according to the data pointer 59 | */ 60 | int jit_fn(char *buf, char **start, off_t offset, 61 | int len, int *eof, void *data) 62 | { 63 | unsigned long j0, j1; /* Jiffies. */ 64 | wait_queue_head_t wait; 65 | 66 | init_waitqueue_head(&wait); 67 | j0 = jiffies; 68 | j1 = j0 + delay; 69 | 70 | switch((long)data) { 71 | case JIT_BUSY: 72 | while (time_before(jiffies, j1)) 73 | cpu_relax(); 74 | break; 75 | case JIT_SCHED: 76 | while (time_before(jiffies, j1)) { 77 | schedule(); 78 | } 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 | len = sprintf(buf, "%9li %9li\n", j0, j1); 91 | *start = buf; 92 | return len; 93 | } 94 | 95 | /* 96 | * This file, on the other hand, returns the current time forever. 97 | */ 98 | int jit_currentime(char *buf, char **start, off_t offset, 99 | int len, int *eof, void *data) 100 | { 101 | struct timeval tv1; 102 | struct timespec tv2; 103 | unsigned long j1; 104 | u64 j2; 105 | 106 | /* Get the time in 4 different ways. */ 107 | j1 = jiffies; 108 | j2 = get_jiffies_64(); 109 | do_gettimeofday(&tv1); 110 | tv2 = current_kernel_time(); 111 | 112 | /* Print. */ 113 | len = 0; 114 | len += sprintf(buf,"0x%08lx 0x%016Lx %10i.%06i\n" 115 | "%40i.%09i\n", 116 | j1, j2, 117 | (int)tv1.tv_sec, (int)tv1.tv_usec, 118 | (int)tv2.tv_sec, (int)tv2.tv_nsec); 119 | *start = buf; 120 | return len; 121 | } 122 | 123 | /* 124 | * The timer example follows. 125 | */ 126 | 127 | /* This data structure is used as "data" for the timer and tasklet functions. */ 128 | struct jit_data { 129 | struct timer_list timer; 130 | struct tasklet_struct tlet; 131 | int hi; /* tasklet or tasklet_hi */ 132 | wait_queue_head_t wait; 133 | unsigned long prevjiffies; 134 | unsigned char *buf; 135 | int loops; 136 | }; 137 | 138 | 139 | void jit_timer_fn(unsigned long arg) 140 | { 141 | struct jit_data *data = (struct jit_data *)arg; 142 | unsigned long j = jiffies; 143 | data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s\n", 144 | j, j - data->prevjiffies, in_interrupt() ? 1 : 0, 145 | current->pid, smp_processor_id(), current->comm); 146 | 147 | if (--data->loops) { 148 | data->timer.expires += tdelay; 149 | data->prevjiffies = j; 150 | add_timer(&data->timer); 151 | } else { 152 | wake_up_interruptible(&data->wait); 153 | } 154 | } 155 | 156 | /* the /proc function: allocate everything to allow concurrency. */ 157 | int jit_timer(char *buf, char **start, off_t offset, 158 | int len, int *eof, void *unused_data) 159 | { 160 | struct jit_data *data; 161 | char *buf2 = buf; 162 | unsigned long j = jiffies; 163 | 164 | data = kmalloc(sizeof(*data), GFP_KERNEL); 165 | if (!data) 166 | return -ENOMEM; 167 | 168 | init_timer(&data->timer); 169 | init_waitqueue_head (&data->wait); 170 | 171 | /* Write the first lines in the buffer. */ 172 | buf2 += sprintf(buf2, " time delta inirq pid cpu command\n"); 173 | buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s\n", 174 | j, 0L, in_interrupt() ? 1 : 0, 175 | current->pid, smp_processor_id(), current->comm); 176 | 177 | /* Fill the data for our timer function. */ 178 | data->prevjiffies = j; 179 | data->buf = buf2; 180 | data->loops = JIT_ASYNC_LOOPS; 181 | 182 | /* Register the timer. */ 183 | data->timer.data = (unsigned long)data; 184 | data->timer.function = jit_timer_fn; 185 | data->timer.expires = j + tdelay; /* Parameter. */ 186 | add_timer(&data->timer); 187 | 188 | /* Wait for the buffer to fill. */ 189 | wait_event_interruptible(data->wait, !data->loops); 190 | if (signal_pending(current)) 191 | return -ERESTARTSYS; 192 | buf2 = data->buf; 193 | kfree(data); 194 | *eof = 1; 195 | return buf2 - buf; 196 | } 197 | 198 | void jit_tasklet_fn(unsigned long arg) 199 | { 200 | struct jit_data *data = (struct jit_data *)arg; 201 | unsigned long j = jiffies; 202 | data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s\n", 203 | j, j - data->prevjiffies, in_interrupt() ? 1 : 0, 204 | current->pid, smp_processor_id(), current->comm); 205 | 206 | if (--data->loops) { 207 | data->prevjiffies = j; 208 | if (data->hi) 209 | tasklet_hi_schedule(&data->tlet); 210 | else 211 | tasklet_schedule(&data->tlet); 212 | } else { 213 | wake_up_interruptible(&data->wait); 214 | } 215 | } 216 | 217 | /* The /proc function: allocate everything to allow concurrency. */ 218 | int jit_tasklet(char *buf, char **start, off_t offset, 219 | int len, int *eof, void *arg) 220 | { 221 | struct jit_data *data; 222 | char *buf2 = buf; 223 | unsigned long j = jiffies; 224 | long hi = (long)arg; 225 | 226 | data = kmalloc(sizeof(*data), GFP_KERNEL); 227 | if (!data) 228 | return -ENOMEM; 229 | 230 | init_waitqueue_head(&data->wait); 231 | 232 | /* Write the first lines in the buffer. */ 233 | buf2 += sprintf(buf2, " time delta inirq pid cpu command\n"); 234 | buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s\n", 235 | j, 0L, in_interrupt() ? 1 : 0, 236 | current->pid, smp_processor_id(), current->comm); 237 | 238 | /* Fill the data for our tasklet function. */ 239 | data->prevjiffies = j; 240 | data->buf = buf2; 241 | data->loops = JIT_ASYNC_LOOPS; 242 | 243 | /* register the tasklet */ 244 | tasklet_init(&data->tlet, jit_tasklet_fn, (unsigned long)data); 245 | data->hi = hi; 246 | if (hi) 247 | tasklet_hi_schedule(&data->tlet); 248 | else 249 | tasklet_schedule(&data->tlet); 250 | 251 | /* Wait for the buffer to fill. */ 252 | wait_event_interruptible(data->wait, !data->loops); 253 | 254 | if (signal_pending(current)) 255 | return -ERESTARTSYS; 256 | buf2 = data->buf; 257 | kfree(data); 258 | *eof = 1; 259 | return buf2 - buf; 260 | } 261 | 262 | 263 | 264 | static int __init jit_init(void) 265 | { 266 | create_proc_read_entry("currentime", 0, NULL, jit_currentime, NULL); 267 | create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); 268 | create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); 269 | create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); 270 | create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); 271 | 272 | create_proc_read_entry("jitimer", 0, NULL, jit_timer, NULL); 273 | create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, NULL); 274 | create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); 275 | 276 | return 0; /* Success. */ 277 | } 278 | 279 | static void __exit jit_cleanup(void) 280 | { 281 | remove_proc_entry("currentime", NULL); 282 | remove_proc_entry("jitbusy", NULL); 283 | remove_proc_entry("jitsched", NULL); 284 | remove_proc_entry("jitqueue", NULL); 285 | remove_proc_entry("jitschedto", NULL); 286 | 287 | remove_proc_entry("jitimer", NULL); 288 | remove_proc_entry("jitasklet", NULL); 289 | remove_proc_entry("jitasklethi", NULL); 290 | } 291 | 292 | module_init(jit_init); 293 | module_exit(jit_cleanup); 294 | -------------------------------------------------------------------------------- /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/seq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple demonstration of the seq_file interface. 3 | * 4 | * $Id: 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 | 15 | MODULE_AUTHOR("Jonathan Corbet"); 16 | MODULE_LICENSE("Dual BSD/GPL"); 17 | 18 | 19 | 20 | /* 21 | * The sequence iterator functions. The position as seen by the 22 | * filesystem is just the count that we return. 23 | */ 24 | static void *ct_seq_start(struct seq_file *s, loff_t *pos) 25 | { 26 | loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL); 27 | if (!spos) 28 | return NULL; 29 | *spos = *pos; 30 | return spos; 31 | } 32 | 33 | static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) 34 | { 35 | loff_t *spos = (loff_t *) v; 36 | *pos = ++(*spos); 37 | return spos; 38 | } 39 | 40 | static void ct_seq_stop(struct seq_file *s, void *v) 41 | { 42 | kfree (v); 43 | } 44 | 45 | /* 46 | * The show function. 47 | */ 48 | static int ct_seq_show(struct seq_file *s, void *v) 49 | { 50 | loff_t *spos = (loff_t *) v; 51 | seq_printf(s, "%Ld\n", *spos); 52 | return 0; 53 | } 54 | 55 | /* 56 | * Tie them all together into a set of seq_operations. 57 | */ 58 | static struct seq_operations ct_seq_ops = { 59 | .start = ct_seq_start, 60 | .next = ct_seq_next, 61 | .stop = ct_seq_stop, 62 | .show = ct_seq_show 63 | }; 64 | 65 | 66 | /* 67 | * Time to set up the file operations for our /proc file. In this case, 68 | * all we need is an open function which sets up the sequence ops. 69 | */ 70 | 71 | static int ct_open(struct inode *inode, struct file *file) 72 | { 73 | return seq_open(file, &ct_seq_ops); 74 | }; 75 | 76 | /* 77 | * The file operations structure contains our open function along with 78 | * set of the canned seq_ ops. 79 | */ 80 | static struct file_operations ct_file_ops = { 81 | .owner = THIS_MODULE, 82 | .open = ct_open, 83 | .read = seq_read, 84 | .llseek = seq_lseek, 85 | .release = seq_release 86 | }; 87 | 88 | 89 | /* 90 | * Module setup and teardown. 91 | */ 92 | 93 | static int ct_init(void) 94 | { 95 | struct proc_dir_entry *entry; 96 | 97 | entry = create_proc_entry("sequence", 0, NULL); 98 | if (entry) 99 | entry->proc_fops = &ct_file_ops; 100 | return 0; 101 | } 102 | 103 | static void ct_exit(void) 104 | { 105 | remove_proc_entry("sequence", NULL); 106 | } 107 | 108 | module_init(ct_init); 109 | module_exit(ct_exit); 110 | -------------------------------------------------------------------------------- /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(filp->f_dentry->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(filp->f_dentry->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 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | MODULE_LICENSE("Dual BSD/GPL"); 28 | 29 | static int sleepy_major = 0; 30 | static int sleepy_minor = 0; 31 | 32 | static DECLARE_WAIT_QUEUE_HEAD(wq); 33 | static int flag = 0; 34 | 35 | ssize_t sleepy_read(struct file *filp, char __user *buf, size_t count, 36 | loff_t *pos) 37 | { 38 | printk(KERN_DEBUG "process %i (%s) going to sleep\n", 39 | current->pid, current->comm); 40 | wait_event_interruptible(wq, flag != 0); 41 | flag = 0; 42 | printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); 43 | return 0; /* EOF */ 44 | } 45 | 46 | ssize_t sleepy_write(struct file *filp, const char __user *buf, size_t count, 47 | loff_t *pos) 48 | { 49 | printk(KERN_DEBUG "process %i (%s) awakening the readers...\n", 50 | current->pid, current->comm); 51 | flag = 1; 52 | wake_up_interruptible(&wq); 53 | return count; /* Succeed, to avoid retrial. */ 54 | } 55 | 56 | struct file_operations sleepy_fops = { 57 | .owner = THIS_MODULE, 58 | .read = sleepy_read, 59 | .write = sleepy_write, 60 | }; 61 | 62 | static int __init sleepy_init(void) 63 | { 64 | int result; 65 | dev_t dev; 66 | struct cdev *sleepy_cdev; 67 | 68 | /* Register dynamically. */ 69 | result = alloc_chrdev_region(&dev, sleepy_minor, 1, "sleepy"); 70 | 71 | if (result < 0) { 72 | printk(KERN_WARNING "sleepy: couldn't get major number assignment\n"); 73 | return result; 74 | } 75 | 76 | sleepy_major = MAJOR(dev); 77 | 78 | sleepy_cdev = cdev_alloc(); 79 | sleepy_cdev->ops = &sleepy_fops; 80 | cdev_add(sleepy_cdev, dev, 1); 81 | 82 | return 0; 83 | } 84 | 85 | static void __exit sleepy_cleanup(void) 86 | { 87 | dev_t dev = MKDEV(sleepy_major, sleepy_minor); 88 | unregister_chrdev_region(dev, 1); 89 | } 90 | 91 | module_init(sleepy_init); 92 | module_exit(sleepy_cleanup); 93 | -------------------------------------------------------------------------------- /misc-progs/Makefile: -------------------------------------------------------------------------------- 1 | 2 | FILES = nbtest load50 mapcmp polltest mapper setlevel setconsole inp outp \ 3 | datasize dataalign netifdebug 4 | 5 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 6 | INCLUDEDIR = $(KERNELDIR)/include 7 | ccflags-y = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR) 8 | 9 | all: $(FILES) 10 | 11 | clean: 12 | rm -f $(FILES) *~ core 13 | 14 | -------------------------------------------------------------------------------- /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 | 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 | # gdbline 4 | # 5 | # Outputs an add-symbol-file line suitable for pasting into gdb to examine 6 | # a loaded module. 7 | # 8 | 9 | if [ "$#" -ne 2 ]; then 10 | echo "Usage: gdbline " 11 | exit 1 12 | fi 13 | 14 | sections_path=/sys/module/$1/sections 15 | 16 | if [ ! -d "$sections_path" ]; then 17 | echo "Unknown module name $1. Is it loaded?" 18 | exit 1 19 | fi 20 | 21 | if [ ! -f "$2" ]; then 22 | echo "Can't find image at $2." 23 | exit 1 24 | fi 25 | 26 | cd $sections_path 27 | echo -n add-symbol-file $2 `/bin/cat .text` 28 | 29 | for section in .[a-z]* *; do 30 | if [ $section != ".text" ]; then 31 | echo " \\" 32 | echo -n " -s" $section `/bin/cat $section` 33 | fi 34 | done 35 | echo 36 | -------------------------------------------------------------------------------- /misc-progs/inp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * inp.c -- read all the ports specified in hex on the command line. 3 | * The program acts as inb/inw/inl according to its own name 4 | * 5 | * Copyright (C) 1998,2000,2001 Alessandro Rubini 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | char *prgname; 34 | 35 | static int read_and_print_one(unsigned int port, int size) 36 | { 37 | static int iopldone = 0; 38 | 39 | if (port > 1024) { 40 | if (!iopldone && iopl(3)) { 41 | fprintf(stderr, "%s: iopl(): %s\n", prgname, strerror(errno)); 42 | return 1; 43 | } 44 | iopldone++; 45 | } else if (ioperm(port, size, 1)) { 46 | fprintf(stderr, "%s: ioperm(%x): %s\n", prgname, 47 | port, strerror(errno)); 48 | return 1; 49 | } 50 | 51 | if (size == 4) 52 | printf("%04x: %08x\n", port, inl(port)); 53 | else if (size == 2) 54 | printf("%04x: %04x\n", port, inw(port)); 55 | else 56 | printf("%04x: %02x\n", port, inb(port)); 57 | return 0; 58 | } 59 | 60 | int main(int argc, char **argv) 61 | { 62 | unsigned int i, n, port, size, error = 0; 63 | 64 | prgname = argv[0]; 65 | /* Find the data size based on the program name. */ 66 | switch (prgname[strlen(prgname) - 1]) { 67 | case 'w': size = 2; break; 68 | case 'l': size = 4; break; 69 | case 'b': case 'p': default: 70 | size = 1; 71 | } 72 | 73 | setuid(0); /* If we're setuid, force it on. */ 74 | for (i = 1; i < argc; i++) { 75 | if (sscanf(argv[i], "%x%n", &port, &n) < 1 76 | || n != strlen(argv[i]) ) { 77 | fprintf(stderr, "%s: argument \"%s\" is not a hex number\n", 78 | argv[0], argv[i]); 79 | error++; continue; 80 | } 81 | if (port & (size - 1)) { 82 | fprintf(stderr, "%s: argument \"%s\" is not properly aligned\n", 83 | argv[0], argv[i]); 84 | error++; continue; 85 | } 86 | error += read_and_print_one(port, size); 87 | } 88 | exit(error ? 1 : 0); 89 | } 90 | 91 | -------------------------------------------------------------------------------- /misc-progs/load50.c: -------------------------------------------------------------------------------- 1 | /* 2 | * load50.c -- a simple busy-looping tool. 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 | int main(int argc, char **argv) 21 | { 22 | int i, load = 50; 23 | 24 | if (argc == 2) { 25 | load = atoi(argv[1]); 26 | } 27 | printf("Increasing load by %i\n", load); 28 | 29 | 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 acts as outb/outw/outl according to its own name. 4 | * 5 | * Copyright (C) 1998,2000,2001 Alessandro Rubini 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | char *prgname; 34 | 35 | static int write_one(unsigned int port, unsigned int val, int size) 36 | { 37 | static int iopldone = 0; 38 | 39 | if (port > 1024) { 40 | if (!iopldone && iopl(3)) { 41 | fprintf(stderr, "%s: iopl(): %s\n", prgname, strerror(errno)); 42 | return 1; 43 | } 44 | iopldone++; 45 | } else if (ioperm(port, size, 1)) { 46 | fprintf(stderr, "%s: ioperm(%x): %s\n", prgname, 47 | port, strerror(errno)); 48 | return 1; 49 | } 50 | 51 | if (size == 4) 52 | outl(val, port); 53 | else if (size == 2) 54 | outw(val & 0xffff, port); 55 | else 56 | outb(val & 0xff, port); 57 | return 0; 58 | } 59 | 60 | int main(int argc, char **argv) 61 | { 62 | unsigned int i, n, port, val, size, error = 0; 63 | 64 | prgname = argv[0]; 65 | /* find the data size */ 66 | switch (prgname[strlen(prgname)-1]) { 67 | case 'w': size = 2; break; 68 | case 'l': size = 4; break; 69 | case 'b': case 'p': default: 70 | size = 1; 71 | } 72 | setuid(0); /* if we're setuid, force it on */ 73 | for (i = 1; i < argc - 1; i++) { 74 | if ( sscanf(argv[i], "%x%n", &port, &n) < 1 75 | || n != strlen(argv[i]) ) { 76 | fprintf(stderr, "%s: argument \"%s\" is not a hex number\n", 77 | argv[0], argv[i]); 78 | error++; continue; 79 | } 80 | if (port & (size - 1)) { 81 | fprintf(stderr, "%s: argument \"%s\" is not properly aligned\n", 82 | argv[0], argv[i]); 83 | error++; continue; 84 | } 85 | if ( sscanf(argv[i+1], "%x%n", &val, &n) < 1 86 | || n != strlen(argv[i+1]) ) { 87 | fprintf(stderr, "%s: argument \"%s\" is not a hex number\n", 88 | argv[0], argv[i+1]); 89 | error++; continue; 90 | } 91 | if (size < 4 && val > (size == 1 ? 0xff : 0xffff)) { 92 | fprintf(stderr, "%s: argument \"%s\" out of range\n", 93 | argv[0], argv[i+1]); 94 | error++; continue; 95 | } 96 | error += write_one(port, val, size); 97 | } 98 | exit(error ? 1 : 0); 99 | } 100 | -------------------------------------------------------------------------------- /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 | /* 11 is the TIOCLINUX subcommand for specifying the console to receive 31 | kernel messages. */ 32 | char bytes[2] = {11, 0}; 33 | 34 | if (argc == 2) { 35 | bytes[1] = atoi(argv[1]); /* The chosen console. */ 36 | } else { 37 | fprintf(stderr, "%s: need a single arg\n", argv[0]); 38 | exit(1); 39 | } 40 | if (ioctl(STDIN_FILENO, TIOCLINUX, bytes) < 0) { /* Use stdin. */ 41 | fprintf(stderr, "%s: ioctl(stdin, TIOCLINUX): %s\n", 42 | argv[0], strerror(errno)); 43 | exit(1); 44 | } 45 | exit(0); 46 | } 47 | -------------------------------------------------------------------------------- /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 | 26 | /* A script to change the console log level. It takes as a command 27 | line argument an integer between 1 and 8 inclusive. Higher numbers 28 | mean more gets printed to the console. */ 29 | 30 | int main(int argc, char **argv) 31 | { 32 | int level; 33 | 34 | if (argc == 2) { 35 | level = atoi(argv[1]); 36 | } else { 37 | fprintf(stderr, "%s: need a single arg\n", argv[0]); 38 | exit(1); 39 | } 40 | /* 8 says we are changing the log level. See the syslog(2) man page for the 41 | full list of actions. */ 42 | if (klogctl(8, NULL, level) < 0) { 43 | fprintf(stderr,"%s: syslog(setlevel): %s\n", argv[0], strerror(errno)); 44 | exit(1); 45 | } 46 | exit(0); 47 | } 48 | -------------------------------------------------------------------------------- /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 11 | 12 | -------------------------------------------------------------------------------- /pci/pci_skel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | static struct pci_device_id ids[] = { 9 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3), }, 10 | { 0, } 11 | }; 12 | MODULE_DEVICE_TABLE(pci, ids); 13 | 14 | static unsigned char skel_get_revision(struct pci_dev *dev) 15 | { 16 | u8 revision; 17 | 18 | pci_read_config_byte(dev, PCI_REVISION_ID, &revision); 19 | return revision; 20 | } 21 | 22 | static int probe(struct pci_dev *dev, const struct pci_device_id *id) 23 | { 24 | /* Do probing type stuff here. 25 | * Like calling request_region(); 26 | */ 27 | pci_enable_device(dev); 28 | 29 | if (skel_get_revision(dev) == 0x42) 30 | return -ENODEV; 31 | 32 | 33 | return 0; 34 | } 35 | 36 | static void remove(struct pci_dev *dev) 37 | { 38 | /* clean up any allocated resources and stuff here. 39 | * like call release_region(); 40 | */ 41 | } 42 | 43 | static struct pci_driver pci_driver = { 44 | .name = "pci_skel", 45 | .id_table = ids, 46 | .probe = probe, 47 | .remove = remove, 48 | }; 49 | 50 | static int __init pci_skel_init(void) 51 | { 52 | return pci_register_driver(&pci_driver); 53 | } 54 | 55 | static void __exit pci_skel_exit(void) 56 | { 57 | pci_unregister_driver(&pci_driver); 58 | } 59 | 60 | MODULE_LICENSE("GPL"); 61 | 62 | module_init(pci_skel_init); 63 | module_exit(pci_skel_exit); 64 | -------------------------------------------------------------------------------- /sbull/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to disable/enable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSBULL_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I.. 13 | 14 | ifneq ($(KERNELRELEASE),) 15 | # call from kernel build system 16 | 17 | obj-m := sbull.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 *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 33 | 34 | depend .depend dep: 35 | $(CC) -M *.c > .depend 36 | 37 | 38 | ifeq (.depend,$(wildcard .depend)) 39 | include .depend 40 | endif 41 | -------------------------------------------------------------------------------- /sbull/sbull.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Sample disk driver, from the beginning. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include /* printk() */ 12 | #include /* kmalloc() */ 13 | #include /* everything... */ 14 | #include /* error codes */ 15 | #include 16 | #include /* size_t */ 17 | #include /* O_ACCMODE */ 18 | #include /* HDIO_GETGEO */ 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include /* invalidate_bdev */ 24 | #include 25 | 26 | MODULE_LICENSE("Dual BSD/GPL"); 27 | 28 | static int sbull_major = 0; 29 | module_param(sbull_major, int, 0); 30 | static int hardsect_size = 512; 31 | module_param(hardsect_size, int, 0); 32 | static int nsectors = 1024; /* How big the drive is */ 33 | module_param(nsectors, int, 0); 34 | static int ndevices = 4; 35 | module_param(ndevices, int, 0); 36 | 37 | /* 38 | * The different "request modes" we can use. 39 | */ 40 | enum { 41 | RM_SIMPLE = 0, /* The extra-simple request function */ 42 | RM_FULL = 1, /* The full-blown version */ 43 | RM_NOQUEUE = 2, /* Use make_request */ 44 | }; 45 | static int request_mode = RM_SIMPLE; 46 | module_param(request_mode, int, 0); 47 | 48 | /* 49 | * Minor number and partition management. 50 | */ 51 | #define SBULL_MINORS 16 52 | #define MINOR_SHIFT 4 53 | #define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT 54 | 55 | /* 56 | * We can tweak our hardware sector size, but the kernel talks to us 57 | * in terms of small sectors, always. 58 | */ 59 | #define KERNEL_SECTOR_SIZE 512 60 | 61 | /* 62 | * After this much idle time, the driver will simulate a media change. 63 | */ 64 | #define INVALIDATE_DELAY 30*HZ 65 | 66 | /* 67 | * The internal representation of our device. 68 | */ 69 | struct sbull_dev { 70 | int size; /* Device size in sectors */ 71 | u8 *data; /* The data array */ 72 | short users; /* How many users */ 73 | short media_change; /* Flag a media change? */ 74 | spinlock_t lock; /* For mutual exclusion */ 75 | struct request_queue *queue; /* The device request queue */ 76 | struct gendisk *gd; /* The gendisk structure */ 77 | struct timer_list timer; /* For simulated media changes */ 78 | }; 79 | 80 | static struct sbull_dev *Devices = NULL; 81 | 82 | /* 83 | * Handle an I/O request. 84 | */ 85 | static void sbull_transfer(struct sbull_dev *dev, unsigned long sector, 86 | unsigned long nsect, char *buffer, int write) 87 | { 88 | unsigned long offset = sector*KERNEL_SECTOR_SIZE; 89 | unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE; 90 | 91 | if ((offset + nbytes) > dev->size) { 92 | printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes); 93 | return; 94 | } 95 | if (write) 96 | memcpy(dev->data + offset, buffer, nbytes); 97 | else 98 | memcpy(buffer, dev->data + offset, nbytes); 99 | } 100 | 101 | /* 102 | * The simple form of the request function. 103 | */ 104 | static void sbull_request(request_queue_t *q) 105 | { 106 | struct request *req; 107 | 108 | while ((req = elv_next_request(q)) != NULL) { 109 | struct sbull_dev *dev = req->rq_disk->private_data; 110 | if (! blk_fs_request(req)) { 111 | printk (KERN_NOTICE "Skip non-fs request\n"); 112 | end_request(req, 0); 113 | continue; 114 | } 115 | // printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n", 116 | // dev - Devices, rq_data_dir(req), 117 | // req->sector, req->current_nr_sectors, 118 | // req->flags); 119 | sbull_transfer(dev, req->sector, req->current_nr_sectors, 120 | req->buffer, rq_data_dir(req)); 121 | end_request(req, 1); 122 | } 123 | } 124 | 125 | 126 | /* 127 | * Transfer a single BIO. 128 | */ 129 | static int sbull_xfer_bio(struct sbull_dev *dev, struct bio *bio) 130 | { 131 | int i; 132 | struct bio_vec *bvec; 133 | sector_t sector = bio->bi_sector; 134 | 135 | /* Do each segment independently. */ 136 | bio_for_each_segment(bvec, bio, i) { 137 | char *buffer = __bio_kmap_atomic(bio, i, KM_USER0); 138 | sbull_transfer(dev, sector, bio_cur_sectors(bio), 139 | buffer, bio_data_dir(bio) == WRITE); 140 | sector += bio_cur_sectors(bio); 141 | __bio_kunmap_atomic(bio, KM_USER0); 142 | } 143 | return 0; /* Always "succeed" */ 144 | } 145 | 146 | /* 147 | * Transfer a full request. 148 | */ 149 | static int sbull_xfer_request(struct sbull_dev *dev, struct request *req) 150 | { 151 | struct bio *bio; 152 | int nsect = 0; 153 | 154 | rq_for_each_bio(bio, req) { 155 | sbull_xfer_bio(dev, bio); 156 | nsect += bio->bi_size/KERNEL_SECTOR_SIZE; 157 | } 158 | return nsect; 159 | } 160 | 161 | 162 | 163 | /* 164 | * Smarter request function that "handles clustering". 165 | */ 166 | static void sbull_full_request(request_queue_t *q) 167 | { 168 | struct request *req; 169 | int sectors_xferred; 170 | struct sbull_dev *dev = q->queuedata; 171 | 172 | while ((req = elv_next_request(q)) != NULL) { 173 | if (! blk_fs_request(req)) { 174 | printk (KERN_NOTICE "Skip non-fs request\n"); 175 | end_request(req, 0); 176 | continue; 177 | } 178 | sectors_xferred = sbull_xfer_request(dev, req); 179 | if (! end_that_request_first(req, 1, sectors_xferred)) { 180 | blkdev_dequeue_request(req); 181 | end_that_request_last(req); 182 | } 183 | } 184 | } 185 | 186 | 187 | 188 | /* 189 | * The direct make request version. 190 | */ 191 | static int sbull_make_request(request_queue_t *q, struct bio *bio) 192 | { 193 | struct sbull_dev *dev = q->queuedata; 194 | int status; 195 | 196 | status = sbull_xfer_bio(dev, bio); 197 | bio_endio(bio, bio->bi_size, status); 198 | return 0; 199 | } 200 | 201 | 202 | /* 203 | * Open and close. 204 | */ 205 | 206 | static int sbull_open(struct inode *inode, struct file *filp) 207 | { 208 | struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data; 209 | 210 | del_timer_sync(&dev->timer); 211 | filp->private_data = dev; 212 | spin_lock(&dev->lock); 213 | if (! dev->users) 214 | check_disk_change(inode->i_bdev); 215 | dev->users++; 216 | spin_unlock(&dev->lock); 217 | return 0; 218 | } 219 | 220 | static int sbull_release(struct inode *inode, struct file *filp) 221 | { 222 | struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data; 223 | 224 | spin_lock(&dev->lock); 225 | dev->users--; 226 | 227 | if (!dev->users) { 228 | dev->timer.expires = jiffies + INVALIDATE_DELAY; 229 | add_timer(&dev->timer); 230 | } 231 | spin_unlock(&dev->lock); 232 | 233 | return 0; 234 | } 235 | 236 | /* 237 | * Look for a (simulated) media change. 238 | */ 239 | int sbull_media_changed(struct gendisk *gd) 240 | { 241 | struct sbull_dev *dev = gd->private_data; 242 | 243 | return dev->media_change; 244 | } 245 | 246 | /* 247 | * Revalidate. WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking 248 | * with open. That needs to be reevaluated. 249 | */ 250 | int sbull_revalidate(struct gendisk *gd) 251 | { 252 | struct sbull_dev *dev = gd->private_data; 253 | 254 | if (dev->media_change) { 255 | dev->media_change = 0; 256 | memset (dev->data, 0, dev->size); 257 | } 258 | return 0; 259 | } 260 | 261 | /* 262 | * The "invalidate" function runs out of the device timer; it sets 263 | * a flag to simulate the removal of the media. 264 | */ 265 | void sbull_invalidate(unsigned long ldev) 266 | { 267 | struct sbull_dev *dev = (struct sbull_dev *) ldev; 268 | 269 | spin_lock(&dev->lock); 270 | if (dev->users || !dev->data) 271 | printk (KERN_WARNING "sbull: timer sanity check failed\n"); 272 | else 273 | dev->media_change = 1; 274 | spin_unlock(&dev->lock); 275 | } 276 | 277 | /* 278 | * The ioctl() implementation 279 | */ 280 | 281 | int sbull_ioctl (struct inode *inode, struct file *filp, 282 | unsigned int cmd, unsigned long arg) 283 | { 284 | long size; 285 | struct hd_geometry geo; 286 | struct sbull_dev *dev = filp->private_data; 287 | 288 | switch(cmd) { 289 | case HDIO_GETGEO: 290 | /* 291 | * Get geometry: since we are a virtual device, we have to make 292 | * up something plausible. So we claim 16 sectors, four heads, 293 | * and calculate the corresponding number of cylinders. We set the 294 | * start of data at sector four. 295 | */ 296 | size = dev->size*(hardsect_size/KERNEL_SECTOR_SIZE); 297 | geo.cylinders = (size & ~0x3f) >> 6; 298 | geo.heads = 4; 299 | geo.sectors = 16; 300 | geo.start = 4; 301 | if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) 302 | return -EFAULT; 303 | return 0; 304 | } 305 | 306 | return -ENOTTY; /* unknown command */ 307 | } 308 | 309 | 310 | 311 | /* 312 | * The device operations structure. 313 | */ 314 | static struct block_device_operations sbull_ops = { 315 | .owner = THIS_MODULE, 316 | .open = sbull_open, 317 | .release = sbull_release, 318 | .media_changed = sbull_media_changed, 319 | .revalidate_disk = sbull_revalidate, 320 | .ioctl = sbull_ioctl 321 | }; 322 | 323 | 324 | /* 325 | * Set up our internal device. 326 | */ 327 | static void setup_device(struct sbull_dev *dev, int which) 328 | { 329 | /* 330 | * Get some memory. 331 | */ 332 | memset (dev, 0, sizeof (struct sbull_dev)); 333 | dev->size = nsectors*hardsect_size; 334 | dev->data = vmalloc(dev->size); 335 | if (dev->data == NULL) { 336 | printk (KERN_NOTICE "vmalloc failure.\n"); 337 | return; 338 | } 339 | spin_lock_init(&dev->lock); 340 | 341 | /* 342 | * The timer which "invalidates" the device. 343 | */ 344 | init_timer(&dev->timer); 345 | dev->timer.data = (unsigned long) dev; 346 | dev->timer.function = sbull_invalidate; 347 | 348 | /* 349 | * The I/O queue, depending on whether we are using our own 350 | * make_request function or not. 351 | */ 352 | switch (request_mode) { 353 | case RM_NOQUEUE: 354 | dev->queue = blk_alloc_queue(GFP_KERNEL); 355 | if (dev->queue == NULL) 356 | goto out_vfree; 357 | blk_queue_make_request(dev->queue, sbull_make_request); 358 | break; 359 | 360 | case RM_FULL: 361 | dev->queue = blk_init_queue(sbull_full_request, &dev->lock); 362 | if (dev->queue == NULL) 363 | goto out_vfree; 364 | break; 365 | 366 | default: 367 | printk(KERN_NOTICE "Bad request mode %d, using simple\n", request_mode); 368 | /* fall into.. */ 369 | 370 | case RM_SIMPLE: 371 | dev->queue = blk_init_queue(sbull_request, &dev->lock); 372 | if (dev->queue == NULL) 373 | goto out_vfree; 374 | break; 375 | } 376 | blk_queue_hardsect_size(dev->queue, hardsect_size); 377 | dev->queue->queuedata = dev; 378 | /* 379 | * And the gendisk structure. 380 | */ 381 | dev->gd = alloc_disk(SBULL_MINORS); 382 | if (! dev->gd) { 383 | printk (KERN_NOTICE "alloc_disk failure\n"); 384 | goto out_vfree; 385 | } 386 | dev->gd->major = sbull_major; 387 | dev->gd->first_minor = which*SBULL_MINORS; 388 | dev->gd->fops = &sbull_ops; 389 | dev->gd->queue = dev->queue; 390 | dev->gd->private_data = dev; 391 | snprintf (dev->gd->disk_name, 32, "sbull%c", which + 'a'); 392 | set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE)); 393 | add_disk(dev->gd); 394 | return; 395 | 396 | out_vfree: 397 | if (dev->data) 398 | vfree(dev->data); 399 | } 400 | 401 | 402 | 403 | static int __init sbull_init(void) 404 | { 405 | int i; 406 | /* 407 | * Get registered. 408 | */ 409 | sbull_major = register_blkdev(sbull_major, "sbull"); 410 | if (sbull_major <= 0) { 411 | printk(KERN_WARNING "sbull: unable to get major number\n"); 412 | return -EBUSY; 413 | } 414 | /* 415 | * Allocate the device array, and initialize each one. 416 | */ 417 | Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL); 418 | if (Devices == NULL) 419 | goto out_unregister; 420 | for (i = 0; i < ndevices; i++) 421 | setup_device(Devices + i, i); 422 | 423 | return 0; 424 | 425 | out_unregister: 426 | unregister_blkdev(sbull_major, "sbd"); 427 | return -ENOMEM; 428 | } 429 | 430 | static void sbull_exit(void) 431 | { 432 | int i; 433 | 434 | for (i = 0; i < ndevices; i++) { 435 | struct sbull_dev *dev = Devices + i; 436 | 437 | del_timer_sync(&dev->timer); 438 | if (dev->gd) { 439 | del_gendisk(dev->gd); 440 | put_disk(dev->gd); 441 | } 442 | if (dev->queue) { 443 | if (request_mode == RM_NOQUEUE) 444 | blk_put_queue(dev->queue); 445 | else 446 | blk_cleanup_queue(dev->queue); 447 | } 448 | if (dev->data) 449 | vfree(dev->data); 450 | } 451 | unregister_blkdev(sbull_major, "sbull"); 452 | kfree(Devices); 453 | } 454 | 455 | module_init(sbull_init); 456 | module_exit(sbull_exit); 457 | -------------------------------------------------------------------------------- /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/sh 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 | /sbin/insmod -f ./$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 | /sbin/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/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to disable/enable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I$(LDDINC) 13 | 14 | ifneq ($(KERNELRELEASE),) 15 | # call from kernel build system 16 | 17 | scull-objs := main.o pipe.o access.o 18 | 19 | obj-m := scull.o 20 | 21 | else 22 | 23 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 24 | PWD := $(shell pwd) 25 | 26 | modules: 27 | $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules 28 | 29 | endif 30 | 31 | 32 | clean: 33 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 34 | 35 | depend .depend dep: 36 | $(CC) -M *.c > .depend 37 | 38 | 39 | ifeq (.depend,$(wildcard .depend)) 40 | include .depend 41 | endif 42 | -------------------------------------------------------------------------------- /scull/access.c: -------------------------------------------------------------------------------- 1 | /* 2 | * access.c -- the files with access control on open 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: access.c,v 1.17 2004/09/26 07:29:56 gregkh Exp $ 16 | */ 17 | 18 | /* FIXME: cloned devices as a use for kobjects? */ 19 | 20 | #include /* printk() */ 21 | #include 22 | #include /* kmalloc() */ 23 | #include /* everything... */ 24 | #include /* error codes */ 25 | #include /* size_t */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "scull.h" /* local definitions */ 35 | 36 | static dev_t scull_a_firstdev; /* Where our range begins */ 37 | 38 | /* 39 | * These devices fall back on the main scull operations. They only 40 | * differ in the implementation of open() and close() 41 | */ 42 | 43 | 44 | 45 | /************************************************************************ 46 | * 47 | * The first device is the single-open one, 48 | * it has an hw structure and an open count 49 | */ 50 | 51 | static struct scull_dev scull_s_device; 52 | static atomic_t scull_s_available = ATOMIC_INIT(1); 53 | 54 | static int scull_s_open(struct inode *inode, struct file *filp) 55 | { 56 | struct scull_dev *dev = &scull_s_device; /* device information */ 57 | 58 | if (! atomic_dec_and_test (&scull_s_available)) { 59 | atomic_inc(&scull_s_available); 60 | return -EBUSY; /* already open */ 61 | } 62 | 63 | /* then, everything else is copied from the bare scull device */ 64 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) 65 | scull_trim(dev); 66 | filp->private_data = dev; 67 | return 0; /* success */ 68 | } 69 | 70 | static int scull_s_release(struct inode *inode, struct file *filp) 71 | { 72 | atomic_inc(&scull_s_available); /* release the device */ 73 | return 0; 74 | } 75 | 76 | 77 | /* 78 | * The other operations for the single-open device come from the bare device 79 | */ 80 | struct file_operations scull_sngl_fops = { 81 | .owner = THIS_MODULE, 82 | .llseek = scull_llseek, 83 | .read = scull_read, 84 | .write = scull_write, 85 | .unlocked_ioctl = scull_ioctl, 86 | .open = scull_s_open, 87 | .release = scull_s_release, 88 | }; 89 | 90 | 91 | /************************************************************************ 92 | * 93 | * Next, the "uid" device. It can be opened multiple times by the 94 | * same user, but access is denied to other users if the device is open 95 | */ 96 | 97 | static struct scull_dev scull_u_device; 98 | static int scull_u_count; /* initialized to 0 by default */ 99 | static uid_t scull_u_owner; /* initialized to 0 by default */ 100 | DEFINE_SPINLOCK(scull_u_lock); 101 | 102 | static int scull_u_open(struct inode *inode, struct file *filp) 103 | { 104 | struct scull_dev *dev = &scull_u_device; /* device information */ 105 | 106 | spin_lock(&scull_u_lock); 107 | if (scull_u_count && 108 | (scull_u_owner != current->cred->uid) && /* allow user */ 109 | (scull_u_owner != current->cred->euid) && /* allow whoever did su */ 110 | !capable(CAP_DAC_OVERRIDE)) { /* still allow root */ 111 | spin_unlock(&scull_u_lock); 112 | return -EBUSY; /* -EPERM would confuse the user */ 113 | } 114 | 115 | if (scull_u_count == 0) 116 | scull_u_owner = current->cred->uid; /* grab it */ 117 | 118 | scull_u_count++; 119 | spin_unlock(&scull_u_lock); 120 | 121 | /* then, everything else is copied from the bare scull device */ 122 | 123 | if ((filp->f_flags & O_ACCMODE) == O_WRONLY) 124 | scull_trim(dev); 125 | filp->private_data = dev; 126 | return 0; /* success */ 127 | } 128 | 129 | static int scull_u_release(struct inode *inode, struct file *filp) 130 | { 131 | spin_lock(&scull_u_lock); 132 | scull_u_count--; /* nothing else */ 133 | spin_unlock(&scull_u_lock); 134 | return 0; 135 | } 136 | 137 | 138 | 139 | /* 140 | * The other operations for the device come from the bare device 141 | */ 142 | struct file_operations scull_user_fops = { 143 | .owner = THIS_MODULE, 144 | .llseek = scull_llseek, 145 | .read = scull_read, 146 | .write = scull_write, 147 | .unlocked_ioctl = scull_ioctl, 148 | .open = scull_u_open, 149 | .release = scull_u_release, 150 | }; 151 | 152 | 153 | /************************************************************************ 154 | * 155 | * Next, the device with blocking-open based on uid 156 | */ 157 | 158 | static struct scull_dev scull_w_device; 159 | static int scull_w_count; /* initialized to 0 by default */ 160 | static uid_t scull_w_owner; /* initialized to 0 by default */ 161 | static DECLARE_WAIT_QUEUE_HEAD(scull_w_wait); 162 | DEFINE_SPINLOCK(scull_w_lock); 163 | 164 | static inline int scull_w_available(void) 165 | { 166 | return scull_w_count == 0 || 167 | scull_w_owner == current->cred->uid || 168 | scull_w_owner == current->cred->euid || 169 | capable(CAP_DAC_OVERRIDE); 170 | } 171 | 172 | 173 | static int scull_w_open(struct inode *inode, struct file *filp) 174 | { 175 | struct scull_dev *dev = &scull_w_device; /* device information */ 176 | 177 | spin_lock(&scull_w_lock); 178 | while (! scull_w_available()) { 179 | spin_unlock(&scull_w_lock); 180 | if (filp->f_flags & O_NONBLOCK) return -EAGAIN; 181 | if (wait_event_interruptible (scull_w_wait, scull_w_available())) 182 | return -ERESTARTSYS; /* tell the fs layer to handle it */ 183 | spin_lock(&scull_w_lock); 184 | } 185 | if (scull_w_count == 0) 186 | scull_w_owner = current->cred->uid; /* grab it */ 187 | scull_w_count++; 188 | spin_unlock(&scull_w_lock); 189 | 190 | /* then, everything else is copied from the bare scull device */ 191 | if ((filp->f_flags & O_ACCMODE) == O_WRONLY) 192 | scull_trim(dev); 193 | filp->private_data = dev; 194 | return 0; /* success */ 195 | } 196 | 197 | static int scull_w_release(struct inode *inode, struct file *filp) 198 | { 199 | int temp; 200 | 201 | spin_lock(&scull_w_lock); 202 | scull_w_count--; 203 | temp = scull_w_count; 204 | spin_unlock(&scull_w_lock); 205 | 206 | if (temp == 0) 207 | wake_up_interruptible_sync(&scull_w_wait); /* awake other uid's */ 208 | return 0; 209 | } 210 | 211 | 212 | /* 213 | * The other operations for the device come from the bare device 214 | */ 215 | struct file_operations scull_wusr_fops = { 216 | .owner = THIS_MODULE, 217 | .llseek = scull_llseek, 218 | .read = scull_read, 219 | .write = scull_write, 220 | .unlocked_ioctl = scull_ioctl, 221 | .open = scull_w_open, 222 | .release = scull_w_release, 223 | }; 224 | 225 | /************************************************************************ 226 | * 227 | * Finally the `cloned' private device. This is trickier because it 228 | * involves list management, and dynamic allocation. 229 | */ 230 | 231 | /* The clone-specific data structure includes a key field */ 232 | 233 | struct scull_listitem { 234 | struct scull_dev device; 235 | dev_t key; 236 | struct list_head list; 237 | 238 | }; 239 | 240 | /* The list of devices, and a lock to protect it */ 241 | static LIST_HEAD(scull_c_list); 242 | DEFINE_SPINLOCK(scull_c_lock); 243 | 244 | /* A placeholder scull_dev which really just holds the cdev stuff. */ 245 | static struct scull_dev scull_c_device; 246 | 247 | /* Look for a device or create one if missing */ 248 | static struct scull_dev *scull_c_lookfor_device(dev_t key) 249 | { 250 | struct scull_listitem *lptr; 251 | 252 | list_for_each_entry(lptr, &scull_c_list, list) { 253 | if (lptr->key == key) 254 | return &(lptr->device); 255 | } 256 | 257 | /* not found */ 258 | lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL); 259 | if (!lptr) 260 | return NULL; 261 | 262 | /* initialize the device */ 263 | memset(lptr, 0, sizeof(struct scull_listitem)); 264 | lptr->key = key; 265 | scull_trim(&(lptr->device)); /* initialize it */ 266 | mutex_init(&(lptr->device.mutex)); 267 | 268 | /* place it in the list */ 269 | list_add(&lptr->list, &scull_c_list); 270 | 271 | return &(lptr->device); 272 | } 273 | 274 | static int scull_c_open(struct inode *inode, struct file *filp) 275 | { 276 | struct scull_dev *dev; 277 | dev_t key; 278 | 279 | if (!current->signal->tty) { 280 | PDEBUG("Process \"%s\" has no ctl tty\n", current->comm); 281 | return -EINVAL; 282 | } 283 | key = tty_devnum(current->signal->tty); 284 | 285 | /* look for a scullc device in the list */ 286 | spin_lock(&scull_c_lock); 287 | dev = scull_c_lookfor_device(key); 288 | spin_unlock(&scull_c_lock); 289 | 290 | if (!dev) 291 | return -ENOMEM; 292 | 293 | /* then, everything else is copied from the bare scull device */ 294 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) 295 | scull_trim(dev); 296 | filp->private_data = dev; 297 | return 0; /* success */ 298 | } 299 | 300 | static int scull_c_release(struct inode *inode, struct file *filp) 301 | { 302 | /* 303 | * Nothing to do, because the device is persistent. 304 | * A `real' cloned device should be freed on last close 305 | */ 306 | return 0; 307 | } 308 | 309 | 310 | 311 | /* 312 | * The other operations for the device come from the bare device 313 | */ 314 | struct file_operations scull_priv_fops = { 315 | .owner = THIS_MODULE, 316 | .llseek = scull_llseek, 317 | .read = scull_read, 318 | .write = scull_write, 319 | .unlocked_ioctl = scull_ioctl, 320 | .open = scull_c_open, 321 | .release = scull_c_release, 322 | }; 323 | 324 | /************************************************************************ 325 | * 326 | * And the init and cleanup functions come last 327 | */ 328 | 329 | static struct scull_adev_info { 330 | char *name; 331 | struct scull_dev *sculldev; 332 | struct file_operations *fops; 333 | } scull_access_devs[] = { 334 | { "scullsingle", &scull_s_device, &scull_sngl_fops }, 335 | { "sculluid", &scull_u_device, &scull_user_fops }, 336 | { "scullwuid", &scull_w_device, &scull_wusr_fops }, 337 | { "sullpriv", &scull_c_device, &scull_priv_fops } 338 | }; 339 | #define SCULL_N_ADEVS 4 340 | 341 | /* 342 | * Set up a single device. 343 | */ 344 | static void scull_access_setup (dev_t devno, struct scull_adev_info *devinfo) 345 | { 346 | struct scull_dev *dev = devinfo->sculldev; 347 | int err; 348 | 349 | /* Initialize the device structure */ 350 | dev->quantum = scull_quantum; 351 | dev->qset = scull_qset; 352 | mutex_init(&dev->mutex); 353 | 354 | /* Do the cdev stuff. */ 355 | cdev_init(&dev->cdev, devinfo->fops); 356 | kobject_set_name(&dev->cdev.kobj, devinfo->name); 357 | dev->cdev.owner = THIS_MODULE; 358 | err = cdev_add (&dev->cdev, devno, 1); 359 | /* Fail gracefully if need be */ 360 | if (err) { 361 | printk(KERN_NOTICE "Error %d adding %s\n", err, devinfo->name); 362 | kobject_put(&dev->cdev.kobj); 363 | } else 364 | printk(KERN_NOTICE "%s registered at %x\n", devinfo->name, devno); 365 | } 366 | 367 | 368 | int scull_access_init(dev_t firstdev) 369 | { 370 | int result, i; 371 | 372 | /* Get our number space */ 373 | result = register_chrdev_region (firstdev, SCULL_N_ADEVS, "sculla"); 374 | if (result < 0) { 375 | printk(KERN_WARNING "sculla: device number registration failed\n"); 376 | return 0; 377 | } 378 | scull_a_firstdev = firstdev; 379 | 380 | /* Set up each device. */ 381 | for (i = 0; i < SCULL_N_ADEVS; i++) 382 | scull_access_setup (firstdev + i, scull_access_devs + i); 383 | return SCULL_N_ADEVS; 384 | } 385 | 386 | /* 387 | * This is called by cleanup_module or on failure. 388 | * It is required to never fail, even if nothing was initialized first 389 | */ 390 | void scull_access_cleanup(void) 391 | { 392 | struct scull_listitem *lptr, *next; 393 | int i; 394 | 395 | /* Clean up the static devs */ 396 | for (i = 0; i < SCULL_N_ADEVS; i++) { 397 | struct scull_dev *dev = scull_access_devs[i].sculldev; 398 | cdev_del(&dev->cdev); 399 | scull_trim(scull_access_devs[i].sculldev); 400 | } 401 | 402 | /* And all the cloned devices */ 403 | list_for_each_entry_safe(lptr, next, &scull_c_list, list) { 404 | list_del(&lptr->list); 405 | scull_trim(&(lptr->device)); 406 | kfree(lptr); 407 | } 408 | 409 | /* Free up our number space */ 410 | unregister_chrdev_region(scull_a_firstdev, SCULL_N_ADEVS); 411 | return; 412 | } 413 | -------------------------------------------------------------------------------- /scull/pipe.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pipe.c -- fifo driver for scull 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 | #include 18 | #include 19 | 20 | #include /* printk(), min() */ 21 | #include /* kmalloc() */ 22 | #include /* everything... */ 23 | #include 24 | #include /* error codes */ 25 | #include /* size_t */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "scull.h" /* local definitions */ 33 | 34 | struct scull_pipe { 35 | wait_queue_head_t inq, outq; /* read and write queues */ 36 | char *buffer, *end; /* begin of buf, end of buf */ 37 | int buffersize; /* used in pointer arithmetic */ 38 | char *rp, *wp; /* where to read, where to write */ 39 | int nreaders, nwriters; /* number of openings for r/w */ 40 | struct fasync_struct *async_queue; /* asynchronous readers */ 41 | struct mutex mutex; /* mutual exclusion semaphore */ 42 | struct cdev cdev; /* Char device structure */ 43 | }; 44 | 45 | /* parameters */ 46 | static int scull_p_nr_devs = SCULL_P_NR_DEVS; /* number of pipe devices */ 47 | int scull_p_buffer = SCULL_P_BUFFER; /* buffer size */ 48 | dev_t scull_p_devno; /* Our first device number */ 49 | 50 | module_param(scull_p_nr_devs, int, 0); /* FIXME check perms */ 51 | module_param(scull_p_buffer, int, 0); 52 | 53 | static struct scull_pipe *scull_p_devices; 54 | 55 | static int scull_p_fasync(int fd, struct file *filp, int mode); 56 | static int spacefree(struct scull_pipe *dev); 57 | /* 58 | * Open and close 59 | */ 60 | 61 | 62 | static int scull_p_open(struct inode *inode, struct file *filp) 63 | { 64 | struct scull_pipe *dev; 65 | 66 | dev = container_of(inode->i_cdev, struct scull_pipe, cdev); 67 | filp->private_data = dev; 68 | 69 | if (mutex_lock_interruptible(&dev->mutex)) 70 | return -ERESTARTSYS; 71 | if (!dev->buffer) { 72 | /* allocate the buffer */ 73 | dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL); 74 | if (!dev->buffer) { 75 | mutex_unlock(&dev->mutex); 76 | return -ENOMEM; 77 | } 78 | } 79 | dev->buffersize = scull_p_buffer; 80 | dev->end = dev->buffer + dev->buffersize; 81 | dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */ 82 | 83 | /* use f_mode,not f_flags: it's cleaner (fs/open.c tells why) */ 84 | if (filp->f_mode & FMODE_READ) 85 | dev->nreaders++; 86 | if (filp->f_mode & FMODE_WRITE) 87 | dev->nwriters++; 88 | mutex_unlock(&dev->mutex); 89 | 90 | return nonseekable_open(inode, filp); 91 | } 92 | 93 | 94 | 95 | static int scull_p_release(struct inode *inode, struct file *filp) 96 | { 97 | struct scull_pipe *dev = filp->private_data; 98 | 99 | /* remove this filp from the asynchronously notified filp's */ 100 | scull_p_fasync(-1, filp, 0); 101 | mutex_lock(&dev->mutex); 102 | if (filp->f_mode & FMODE_READ) 103 | dev->nreaders--; 104 | if (filp->f_mode & FMODE_WRITE) 105 | dev->nwriters--; 106 | if (dev->nreaders + dev->nwriters == 0) { 107 | kfree(dev->buffer); 108 | dev->buffer = NULL; /* the other fields are not checked on open */ 109 | } 110 | mutex_unlock(&dev->mutex); 111 | return 0; 112 | } 113 | 114 | 115 | /* 116 | * Data management: read and write 117 | */ 118 | 119 | static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count, 120 | loff_t *f_pos) 121 | { 122 | struct scull_pipe *dev = filp->private_data; 123 | 124 | if (mutex_lock_interruptible(&dev->mutex)) 125 | return -ERESTARTSYS; 126 | 127 | while (dev->rp == dev->wp) { /* nothing to read */ 128 | mutex_unlock(&dev->mutex); /* release the lock */ 129 | if (filp->f_flags & O_NONBLOCK) { 130 | PDEBUG("\"%s\" nonblocking read: returning EAGAIN\n", 131 | current->comm); 132 | return -EAGAIN; 133 | } 134 | PDEBUG("\"%s\" reading: going to sleep\n", current->comm); 135 | if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp))) 136 | return -ERESTARTSYS; /* signal: tell the fs layer to handle it */ 137 | /* otherwise loop, but first reacquire the lock */ 138 | if (mutex_lock_interruptible(&dev->mutex)) 139 | return -ERESTARTSYS; 140 | } 141 | /* ok, data is there, return something */ 142 | if (dev->wp > dev->rp) 143 | count = min(count, (size_t)(dev->wp - dev->rp)); 144 | else /* the write pointer has wrapped, return data up to dev->end */ 145 | count = min(count, (size_t)(dev->end - dev->rp)); 146 | if (copy_to_user(buf, dev->rp, count)) { 147 | mutex_unlock(&dev->mutex); 148 | return -EFAULT; 149 | } 150 | dev->rp += count; 151 | if (dev->rp == dev->end) 152 | dev->rp = dev->buffer; /* wrapped */ 153 | mutex_unlock(&dev->mutex); 154 | 155 | /* finally, awake any writers and return */ 156 | wake_up_interruptible(&dev->outq); 157 | PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count); 158 | return count; 159 | } 160 | 161 | /* Wait for space for writing; caller must hold device mutex. On 162 | * error the mutex will be released before returning. */ 163 | static int scull_getwritespace(struct scull_pipe *dev, struct file *filp) 164 | { 165 | while (spacefree(dev) == 0) { /* full */ 166 | DEFINE_WAIT(wait); 167 | 168 | mutex_unlock(&dev->mutex); 169 | if (filp->f_flags & O_NONBLOCK) { 170 | PDEBUG("\"%s\" nonblocking write: returning EAGAIN\n", 171 | current->comm); 172 | return -EAGAIN; 173 | } 174 | PDEBUG("\"%s\" writing: going to sleep\n",current->comm); 175 | prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE); 176 | if (spacefree(dev) == 0) 177 | schedule(); 178 | finish_wait(&dev->outq, &wait); 179 | if (signal_pending(current)) 180 | return -ERESTARTSYS; /* signal: tell the fs layer to handle it */ 181 | if (mutex_lock_interruptible(&dev->mutex)) 182 | return -ERESTARTSYS; 183 | } 184 | return 0; 185 | } 186 | 187 | /* How much space is free? */ 188 | static int spacefree(struct scull_pipe *dev) 189 | { 190 | if (dev->rp == dev->wp) 191 | return dev->buffersize - 1; 192 | return ((dev->rp + dev->buffersize - dev->wp) % dev->buffersize) - 1; 193 | } 194 | 195 | static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count, 196 | loff_t *f_pos) 197 | { 198 | struct scull_pipe *dev = filp->private_data; 199 | int result; 200 | 201 | if (mutex_lock_interruptible(&dev->mutex)) 202 | return -ERESTARTSYS; 203 | 204 | /* Make sure there's space to write */ 205 | result = scull_getwritespace(dev, filp); 206 | if (result) 207 | return result; /* scull_getwritespace called mutex_unlock(&dev->mutex) */ 208 | 209 | /* ok, space is there, accept something */ 210 | count = min(count, (size_t)spacefree(dev)); 211 | if (dev->wp >= dev->rp) 212 | count = min(count, (size_t)(dev->end - dev->wp)); /* to end-of-buf */ 213 | else /* the write pointer has wrapped, fill up to rp-1 */ 214 | count = min(count, (size_t)(dev->rp - dev->wp - 1)); 215 | PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev->wp, buf); 216 | if (copy_from_user(dev->wp, buf, count)) { 217 | mutex_unlock(&dev->mutex); 218 | return -EFAULT; 219 | } 220 | dev->wp += count; 221 | if (dev->wp == dev->end) 222 | dev->wp = dev->buffer; /* wrapped */ 223 | mutex_unlock(&dev->mutex); 224 | 225 | /* finally, awake any reader */ 226 | wake_up_interruptible(&dev->inq); /* blocked in read() and select() */ 227 | 228 | /* and signal asynchronous readers, explained late in chapter 5 */ 229 | if (dev->async_queue) 230 | kill_fasync(&dev->async_queue, SIGIO, POLL_IN); 231 | PDEBUG("\"%s\" did write %li bytes\n",current->comm, (long)count); 232 | return count; 233 | } 234 | 235 | static unsigned int scull_p_poll(struct file *filp, poll_table *wait) 236 | { 237 | struct scull_pipe *dev = filp->private_data; 238 | unsigned int mask = 0; 239 | 240 | /* 241 | * The buffer is circular; it is considered full 242 | * if "wp" is right behind "rp" and empty if the 243 | * two are equal. 244 | */ 245 | mutex_lock(&dev->mutex); 246 | poll_wait(filp, &dev->inq, wait); 247 | poll_wait(filp, &dev->outq, wait); 248 | if (dev->rp != dev->wp) 249 | mask |= POLLIN | POLLRDNORM; /* readable */ 250 | if (spacefree(dev)) 251 | mask |= POLLOUT | POLLWRNORM; /* writable */ 252 | mutex_unlock(&dev->mutex); 253 | return mask; 254 | } 255 | 256 | 257 | 258 | 259 | 260 | static int scull_p_fasync(int fd, struct file *filp, int mode) 261 | { 262 | struct scull_pipe *dev = filp->private_data; 263 | 264 | return fasync_helper(fd, filp, mode, &dev->async_queue); 265 | } 266 | 267 | 268 | 269 | /* FIXME this should use seq_file */ 270 | #ifdef SCULL_DEBUG 271 | static void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len) 272 | { 273 | if (*offset == 0) 274 | return; 275 | if (*offset >= *len) { /* Not there yet */ 276 | *offset -= *len; 277 | *len = 0; 278 | } 279 | else { /* We're into the interesting stuff now */ 280 | *start = buf + *offset; 281 | *offset = 0; 282 | } 283 | } 284 | 285 | 286 | static int scull_read_p_mem(char *buf, char **start, off_t offset, int count, 287 | int *eof, void *data) 288 | { 289 | int i, len; 290 | struct scull_pipe *p; 291 | 292 | #define LIMIT (PAGE_SIZE-200) /* don't print any more after this size */ 293 | *start = buf; 294 | len = sprintf(buf, "Default buffersize is %i\n", scull_p_buffer); 295 | for(i = 0; imutex)) 298 | return -ERESTARTSYS; 299 | len += sprintf(buf+len, "\nDevice %i: %p\n", i, p); 300 | /* len += sprintf(buf+len, " Queues: %p %p\n", p->inq, p->outq);*/ 301 | len += sprintf(buf+len, " Buffer: %p to %p (%i bytes)\n", p->buffer, p->end, p->buffersize); 302 | len += sprintf(buf+len, " rp %p wp %p\n", p->rp, p->wp); 303 | len += sprintf(buf+len, " readers %i writers %i\n", p->nreaders, p->nwriters); 304 | mutex_unlock(&p->mutex); 305 | scullp_proc_offset(buf, start, &offset, &len); 306 | } 307 | *eof = (len <= LIMIT); 308 | return len; 309 | } 310 | 311 | 312 | #endif 313 | 314 | 315 | 316 | /* 317 | * The file operations for the pipe device 318 | * (some are overlayed with bare scull) 319 | */ 320 | struct file_operations scull_pipe_fops = { 321 | .owner = THIS_MODULE, 322 | .llseek = no_llseek, 323 | .read = scull_p_read, 324 | .write = scull_p_write, 325 | .poll = scull_p_poll, 326 | .unlocked_ioctl = scull_ioctl, 327 | .open = scull_p_open, 328 | .release = scull_p_release, 329 | .fasync = scull_p_fasync, 330 | }; 331 | 332 | 333 | /* 334 | * Set up a cdev entry. 335 | */ 336 | static void scull_p_setup_cdev(struct scull_pipe *dev, int index) 337 | { 338 | int err, devno = scull_p_devno + index; 339 | 340 | cdev_init(&dev->cdev, &scull_pipe_fops); 341 | dev->cdev.owner = THIS_MODULE; 342 | err = cdev_add (&dev->cdev, devno, 1); 343 | /* Fail gracefully if need be */ 344 | if (err) 345 | printk(KERN_NOTICE "Error %d adding scullpipe%d", err, index); 346 | } 347 | 348 | 349 | 350 | /* 351 | * Initialize the pipe devs; return how many we did. 352 | */ 353 | int scull_p_init(dev_t firstdev) 354 | { 355 | int i, result; 356 | 357 | result = register_chrdev_region(firstdev, scull_p_nr_devs, "scullp"); 358 | if (result < 0) { 359 | printk(KERN_NOTICE "Unable to get scullp region, error %d\n", result); 360 | return 0; 361 | } 362 | scull_p_devno = firstdev; 363 | scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(struct scull_pipe), GFP_KERNEL); 364 | if (scull_p_devices == NULL) { 365 | unregister_chrdev_region(firstdev, scull_p_nr_devs); 366 | return 0; 367 | } 368 | memset(scull_p_devices, 0, scull_p_nr_devs * sizeof(struct scull_pipe)); 369 | for (i = 0; i < scull_p_nr_devs; i++) { 370 | init_waitqueue_head(&(scull_p_devices[i].inq)); 371 | init_waitqueue_head(&(scull_p_devices[i].outq)); 372 | mutex_init(&scull_p_devices[i].mutex); 373 | scull_p_setup_cdev(scull_p_devices + i, i); 374 | } 375 | #ifdef SCULL_DEBUG 376 | create_proc_read_entry("scullpipe", 0, NULL, scull_read_p_mem, NULL); 377 | #endif 378 | return scull_p_nr_devs; 379 | } 380 | 381 | /* 382 | * This is called by cleanup_module or on failure. 383 | * It is required to never fail, even if nothing was initialized first 384 | */ 385 | void scull_p_cleanup(void) 386 | { 387 | int i; 388 | 389 | #ifdef SCULL_DEBUG 390 | remove_proc_entry("scullpipe", NULL); 391 | #endif 392 | 393 | if (!scull_p_devices) 394 | return; /* nothing else to release */ 395 | 396 | for (i = 0; i < scull_p_nr_devs; i++) { 397 | cdev_del(&scull_p_devices[i].cdev); 398 | kfree(scull_p_devices[i].buffer); 399 | } 400 | kfree(scull_p_devices); 401 | unregister_chrdev_region(scull_p_devno, scull_p_nr_devs); 402 | scull_p_devices = NULL; /* pedantic */ 403 | } 404 | -------------------------------------------------------------------------------- /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 | */ 16 | 17 | #ifndef _SCULL_H_ 18 | #define _SCULL_H_ 19 | 20 | /* Gives us access to ioctl macros _IO and friends below. */ 21 | #include 22 | #include 23 | 24 | /* 25 | * Macros to help with debugging. Set SCULL_DEBUG to 1 enable 26 | * debugging (which you can do from the Makefile); these macros work 27 | * in both kernelspace and userspace. 28 | */ 29 | 30 | #undef PDEBUG /* undef it, just in case someone else defined it. */ 31 | #ifdef SCULL_DEBUG 32 | # ifdef __KERNEL__ 33 | /* Debugging is on and we are in kernelspace. */ 34 | # define PDEBUG(fmt, args...) printk(KERN_DEBUG "scull: " fmt, ## args) 35 | # else 36 | /* Debugging is on and we are in userspace. */ 37 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args) 38 | # endif 39 | #else 40 | # define PDEBUG(fmt, args...) /* Not debugging: do nothing. */ 41 | #endif 42 | 43 | /* PDEBUGG is a placeholder that makes it easy to "comment out" the debugging 44 | statements without deleting them. */ 45 | #undef PDEBUGG 46 | #define PDEBUGG(fmt, args...) 47 | 48 | #ifndef SCULL_MAJOR 49 | #define SCULL_MAJOR 0 /* dynamic major by default */ 50 | #endif 51 | 52 | #ifndef SCULL_NR_DEVS 53 | #define SCULL_NR_DEVS 4 /* scull0 through scull3 */ 54 | #endif 55 | 56 | #ifndef SCULL_P_NR_DEVS 57 | #define SCULL_P_NR_DEVS 4 /* scullpipe0 through scullpipe3 */ 58 | #endif 59 | 60 | /* 61 | * The bare device is a variable-length region of memory. Use a 62 | * linked list of indirect blocks. 63 | * 64 | * "scull_dev->data" points to an array of pointers, each pointer 65 | * refers to a memory area of SCULL_QUANTUM bytes. 66 | * 67 | * The array (quantum-set) is SCULL_QSET long. 68 | */ 69 | #ifndef SCULL_QUANTUM 70 | #define SCULL_QUANTUM 4000 71 | #endif 72 | 73 | #ifndef SCULL_QSET 74 | #define SCULL_QSET 1000 75 | #endif 76 | 77 | /* 78 | * The pipe device is a simple circular buffer. Here its default size 79 | */ 80 | #ifndef SCULL_P_BUFFER 81 | #define SCULL_P_BUFFER 4000 82 | #endif 83 | 84 | /* 85 | * Representation of scull quantum sets. 86 | */ 87 | struct scull_qset { 88 | void **data; 89 | struct scull_qset *next; 90 | }; 91 | 92 | struct scull_dev { 93 | struct scull_qset *data; /* Pointer to first quantum set. */ 94 | int quantum; /* The current quantum size. */ 95 | int qset; /* The current array size. */ 96 | unsigned long size; /* Amount of data stored here. */ 97 | unsigned int access_key; /* Used by sculluid and scullpriv. */ 98 | struct mutex mutex; /* Mutual exclusion semaphore. */ 99 | struct cdev cdev; /* Char device structure. */ 100 | }; 101 | 102 | /* 103 | * Split minors in two parts 104 | */ 105 | #define TYPE(minor) (((minor) >> 4) & 0xf) /* high nibble */ 106 | #define NUM(minor) ((minor) & 0xf) /* low nibble */ 107 | 108 | 109 | /* 110 | * The different configurable parameters 111 | */ 112 | extern int scull_major; /* main.c */ 113 | extern int scull_nr_devs; 114 | extern int scull_quantum; 115 | extern int scull_qset; 116 | 117 | extern int scull_p_buffer; /* pipe.c */ 118 | 119 | 120 | /* 121 | * Prototypes for shared functions 122 | */ 123 | 124 | int scull_p_init(dev_t dev); 125 | void scull_p_cleanup(void); 126 | int scull_access_init(dev_t dev); 127 | void scull_access_cleanup(void); 128 | 129 | int scull_trim(struct scull_dev *dev); 130 | 131 | ssize_t scull_read(struct file *filp, char __user *buf, size_t count, 132 | loff_t *f_pos); 133 | ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, 134 | loff_t *f_pos); 135 | loff_t scull_llseek(struct file *filp, loff_t off, int whence); 136 | long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 137 | 138 | 139 | /* 140 | * Ioctl definitions 141 | */ 142 | 143 | /* Use 'k' as magic number */ 144 | #define SCULL_IOC_MAGIC 'k' 145 | /* Please use a different 8-bit number in your code */ 146 | 147 | #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0) 148 | 149 | /* 150 | * S means "Set" through a ptr, 151 | * T means "Tell" directly with the argument value 152 | * G means "Get": reply by setting through a pointer 153 | * Q means "Query": response is on the return value 154 | * X means "eXchange": switch G and S atomically 155 | * H means "sHift": switch T and Q atomically 156 | */ 157 | #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int) 158 | #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int) 159 | #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3) 160 | #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4) 161 | #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int) 162 | #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int) 163 | #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7) 164 | #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8) 165 | #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int) 166 | #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int) 167 | #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11) 168 | #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12) 169 | 170 | /* 171 | * The other entities only have "Tell" and "Query", because they're 172 | * not printed in the book, and there's no need to have all six. 173 | * (The previous stuff was only there to show different ways to do it. 174 | */ 175 | #define SCULL_P_IOCTSIZE _IO(SCULL_IOC_MAGIC, 13) 176 | #define SCULL_P_IOCQSIZE _IO(SCULL_IOC_MAGIC, 14) 177 | /* ... more to come */ 178 | 179 | #define SCULL_IOC_MAXNR 14 180 | 181 | #endif /* _SCULL_H_ */ 182 | -------------------------------------------------------------------------------- /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. Options 23 | # cannot be specified via the command line. Instead, define them in in 24 | # /etc/${DEVICE}.conf or (if modprobe is used) /etc/modules.conf. 25 | 26 | # Optional configuration file: format is 27 | # owner 28 | # group 29 | # mode 30 | # options 31 | CFG=/etc/${DEVICE}.conf 32 | 33 | # The kernel version, used to look for modules. 34 | KERNEL=`uname -r` 35 | 36 | MODDIR="/lib/modules/${KERNEL}/kernel/drivers/${SECTION}" 37 | if [ ! -d $MODDIR ]; then 38 | MODDIR="/lib/modules/${KERNEL}/${SECTION}" 39 | fi 40 | 41 | if [ "$(id -u)" != "0" ]; then 42 | echo "You must be root to load or unload kernel modules" 43 | exit 1 44 | fi 45 | 46 | # Read options out of the configuration file. 47 | if [ -r $CFG ]; then 48 | OWNER=`awk "\\$1==\"owner\" {print \\$2}" $CFG` 49 | GROUP=`awk "\\$1==\"group\" {print \\$2}" $CFG` 50 | MODE=`awk "\\$1==\"mode\" {print \\$2}" $CFG` 51 | # The options string may include extra blanks or only blanks. 52 | OPTIONS=`sed -n '/^options / s/options //p' $CFG` 53 | fi 54 | 55 | 56 | # Create device files. 57 | function create_files () { 58 | cd /dev 59 | local devlist="" 60 | local file 61 | while true; do 62 | if [ $# -lt 2 ]; then break; fi 63 | file="${DEVICE}$1" 64 | mknod $file c $MAJOR $2 65 | devlist="$devlist $file" 66 | shift 2 67 | done 68 | if [ -n "$OWNER" ]; then chown $OWNER $devlist; fi 69 | if [ -n "$GROUP" ]; then chgrp $GROUP $devlist; fi 70 | if [ -n "$MODE" ]; then chmod $MODE $devlist; fi 71 | } 72 | 73 | # Remove device files. 74 | function remove_files () { 75 | cd /dev 76 | local devlist="" 77 | local file 78 | while true; do 79 | if [ $# -lt 2 ]; then 80 | break 81 | fi 82 | file="${DEVICE}$1" 83 | devlist="$devlist $file" 84 | shift 2 85 | done 86 | rm -f $devlist 87 | } 88 | 89 | # Load and create files. 90 | function load_device () { 91 | if [ -f $MODDIR/$DEVICE.ko ]; then 92 | devpath=$MODDIR/$DEVICE.ko 93 | elif [ -f ./$DEVICE.ko ]; then 94 | devpath=./$DEVICE.ko 95 | else 96 | devpath=$DEVICE # Let insmod/modprobe guess. 97 | 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 | 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 provided arguments. Use a pathname, as insmod doesn't 15 | # look in . by default. 16 | /sbin/insmod ./$module.ko $* || exit 1 17 | 18 | # Retrieve the device 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 | 23 | # Usually a load script is shorter; scull just has a lot of associated devices. 24 | 25 | rm -f /dev/${device}[0-3] 26 | mknod /dev/${device}0 c $major 0 27 | mknod /dev/${device}1 c $major 1 28 | mknod /dev/${device}2 c $major 2 29 | mknod /dev/${device}3 c $major 3 30 | ln -sf ${device}0 /dev/${device} 31 | chgrp $group /dev/${device}[0-3] 32 | chmod $mode /dev/${device}[0-3] 33 | 34 | rm -f /dev/${device}pipe[0-3] 35 | mknod /dev/${device}pipe0 c $major 4 36 | mknod /dev/${device}pipe1 c $major 5 37 | mknod /dev/${device}pipe2 c $major 6 38 | mknod /dev/${device}pipe3 c $major 7 39 | ln -sf ${device}pipe0 /dev/${device}pipe 40 | chgrp $group /dev/${device}pipe[0-3] 41 | chmod $mode /dev/${device}pipe[0-3] 42 | 43 | rm -f /dev/${device}single 44 | mknod /dev/${device}single c $major 8 45 | chgrp $group /dev/${device}single 46 | chmod $mode /dev/${device}single 47 | 48 | rm -f /dev/${device}uid 49 | mknod /dev/${device}uid c $major 9 50 | chgrp $group /dev/${device}uid 51 | chmod $mode /dev/${device}uid 52 | 53 | rm -f /dev/${device}wuid 54 | mknod /dev/${device}wuid c $major 10 55 | chgrp $group /dev/${device}wuid 56 | chmod $mode /dev/${device}wuid 57 | 58 | rm -f /dev/${device}priv 59 | mknod /dev/${device}priv c $major 11 60 | chgrp $group /dev/${device}priv 61 | chmod $mode /dev/${device}priv 62 | -------------------------------------------------------------------------------- /scull/scull_unload: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | module="scull" 4 | device="scull" 5 | 6 | # Invoke rmmod with all provided arguments. 7 | /sbin/rmmod $module $* || exit 1 8 | 9 | # Remove stale nodes. 10 | 11 | rm -f /dev/${device} /dev/${device}[0-3] 12 | rm -f /dev/${device}priv 13 | rm -f /dev/${device}pipe /dev/${device}pipe[0-3] 14 | rm -f /dev/${device}single 15 | rm -f /dev/${device}uid 16 | rm -f /dev/${device}wuid 17 | -------------------------------------------------------------------------------- /scullc/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to enable/disable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSCULLC_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I$(LDDINC) 13 | 14 | TARGET = scullc 15 | 16 | ifneq ($(KERNELRELEASE),) 17 | 18 | scullc-objs := main.o 19 | 20 | obj-m := scullc.o 21 | 22 | else 23 | 24 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 25 | PWD := $(shell pwd) 26 | 27 | modules: 28 | $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD) modules 29 | 30 | endif 31 | 32 | 33 | install: 34 | install -d $(INSTALLDIR) 35 | install -c $(TARGET).o $(INSTALLDIR) 36 | 37 | clean: 38 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 39 | 40 | 41 | depend .depend dep: 42 | $(CC) -M *.c > .depend 43 | 44 | ifeq (.depend,$(wildcard .depend)) 45 | include .depend 46 | endif 47 | -------------------------------------------------------------------------------- /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 | #include 20 | 21 | #include /* everything */ 22 | #include /* error codes */ 23 | #include 24 | 25 | #include "scullc.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 scullc_vma_open(struct vm_area_struct *vma) 34 | { 35 | struct scullc_dev *dev = vma->vm_private_data; 36 | 37 | dev->vmas++; 38 | } 39 | 40 | void scullc_vma_close(struct vm_area_struct *vma) 41 | { 42 | struct scullc_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 scullc 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 | 60 | struct page *scullc_vma_nopage(struct vm_area_struct *vma, 61 | unsigned long address, int *type) 62 | { 63 | unsigned long offset; 64 | struct scullc_dev *ptr, *dev = vma->vm_private_data; 65 | struct page *page = NOPAGE_SIGBUS; 66 | void *pageptr = NULL; /* default to "missing" */ 67 | 68 | down(&dev->sem); 69 | offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 70 | if (offset >= dev->size) goto out; /* out of range */ 71 | 72 | /* 73 | * Now retrieve the scullc device from the list,then the page. 74 | * If the device has holes, the process receives a SIGBUS when 75 | * accessing the hole. 76 | */ 77 | offset >>= PAGE_SHIFT; /* offset is a number of pages */ 78 | for (ptr = dev; ptr && offset >= dev->qset;) { 79 | ptr = ptr->next; 80 | offset -= dev->qset; 81 | } 82 | if (ptr && ptr->data) pageptr = ptr->data[offset]; 83 | if (!pageptr) goto out; /* hole or end-of-file */ 84 | 85 | /* got it, now increment the count */ 86 | get_page(page); 87 | if (type) 88 | *type = VM_FAULT_MINOR; 89 | out: 90 | up(&dev->sem); 91 | return page; 92 | } 93 | 94 | 95 | 96 | struct vm_operations_struct scullc_vm_ops = { 97 | .open = scullc_vma_open, 98 | .close = scullc_vma_close, 99 | .nopage = scullc_vma_nopage, 100 | }; 101 | 102 | 103 | int scullc_mmap(struct file *filp, struct vm_area_struct *vma) 104 | { 105 | struct inode *inode = filp->f_dentry->d_inode; 106 | 107 | /* refuse to map if order is not 0 */ 108 | if (scullc_devices[iminor(inode)].order) 109 | return -ENODEV; 110 | 111 | /* don't do anything here: "nopage" will set up page table entries */ 112 | vma->vm_ops = &scullc_vm_ops; 113 | vma->vm_flags |= VM_RESERVED; 114 | vma->vm_private_data = filp->private_data; 115 | scullc_vma_open(vma); 116 | return 0; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /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 semaphore sem; /* 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 | /sbin/insmod -f ./$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 | /sbin/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 | # Comment/uncomment the following line to enable/disable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSCULLD_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I$(LDDINC) 13 | 14 | TARGET = sculld 15 | 16 | ifneq ($(KERNELRELEASE),) 17 | 18 | sculld-objs := main.o mmap.o 19 | 20 | obj-m := sculld.o 21 | 22 | else 23 | 24 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 25 | PWD := $(shell pwd) 26 | 27 | modules: 28 | $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD) modules 29 | 30 | endif 31 | 32 | 33 | install: 34 | install -d $(INSTALLDIR) 35 | install -c $(TARGET).o $(INSTALLDIR) 36 | 37 | clean: 38 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 39 | 40 | 41 | depend .depend dep: 42 | $(CC) -M *.c > .depend 43 | 44 | ifeq (.depend,$(wildcard .depend)) 45 | include .depend 46 | endif 47 | -------------------------------------------------------------------------------- /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 | 21 | #include /* everything */ 22 | #include /* error codes */ 23 | #include 24 | 25 | #include "sculld.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 sculld_vma_open(struct vm_area_struct *vma) 34 | { 35 | struct sculld_dev *dev = vma->vm_private_data; 36 | 37 | dev->vmas++; 38 | } 39 | 40 | void sculld_vma_close(struct vm_area_struct *vma) 41 | { 42 | struct sculld_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 sculld 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 | 60 | struct page *sculld_vma_nopage(struct vm_area_struct *vma, 61 | unsigned long address, int *type) 62 | { 63 | unsigned long offset; 64 | struct sculld_dev *ptr, *dev = vma->vm_private_data; 65 | struct page *page = NOPAGE_SIGBUS; 66 | void *pageptr = NULL; /* default to "missing" */ 67 | 68 | down(&dev->sem); 69 | offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 70 | if (offset >= dev->size) goto out; /* out of range */ 71 | 72 | /* 73 | * Now retrieve the sculld device from the list,then the page. 74 | * If the device has holes, the process receives a SIGBUS when 75 | * accessing the hole. 76 | */ 77 | offset >>= PAGE_SHIFT; /* offset is a number of pages */ 78 | for (ptr = dev; ptr && offset >= dev->qset;) { 79 | ptr = ptr->next; 80 | offset -= dev->qset; 81 | } 82 | if (ptr && ptr->data) pageptr = ptr->data[offset]; 83 | if (!pageptr) goto out; /* hole or end-of-file */ 84 | 85 | /* got it, now increment the count */ 86 | get_page(page); 87 | if (type) 88 | *type = VM_FAULT_MINOR; 89 | out: 90 | up(&dev->sem); 91 | return page; 92 | } 93 | 94 | 95 | 96 | struct vm_operations_struct sculld_vm_ops = { 97 | .open = sculld_vma_open, 98 | .close = sculld_vma_close, 99 | .nopage = sculld_vma_nopage, 100 | }; 101 | 102 | 103 | int sculld_mmap(struct file *filp, struct vm_area_struct *vma) 104 | { 105 | struct inode *inode = filp->f_dentry->d_inode; 106 | 107 | /* refuse to map if order is not 0 */ 108 | if (sculld_devices[iminor(inode)].order) 109 | return -ENODEV; 110 | 111 | /* don't do anything here: "nopage" will set up page table entries */ 112 | vma->vm_ops = &sculld_vm_ops; 113 | vma->vm_flags |= VM_RESERVED; 114 | vma->vm_private_data = filp->private_data; 115 | sculld_vma_open(vma); 116 | return 0; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /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 semaphore sem; /* 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 | /sbin/insmod -f ./$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 | -------------------------------------------------------------------------------- /sculld/sculld_unload: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | module="sculld" 3 | device="sculld" 4 | 5 | # invoke rmmod with all arguments we got 6 | /sbin/rmmod $module $* || exit 1 7 | 8 | # remove nodes 9 | rm -f /dev/${device}[0-3] /dev/${device} 10 | 11 | exit 0 12 | -------------------------------------------------------------------------------- /scullp/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to enable/disable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSCULLP_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I$(LDDINC) 13 | 14 | TARGET = scullp 15 | 16 | ifneq ($(KERNELRELEASE),) 17 | 18 | scullp-objs := main.o mmap.o 19 | 20 | obj-m := scullp.o 21 | 22 | else 23 | 24 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 25 | PWD := $(shell pwd) 26 | 27 | modules: 28 | $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD) modules 29 | 30 | endif 31 | 32 | 33 | install: 34 | install -d $(INSTALLDIR) 35 | install -c $(TARGET).o $(INSTALLDIR) 36 | 37 | clean: 38 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 39 | 40 | 41 | depend .depend dep: 42 | $(CC) -M *.c > .depend 43 | 44 | ifeq (.depend,$(wildcard .depend)) 45 | include .depend 46 | endif 47 | -------------------------------------------------------------------------------- /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 | 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 | 60 | int scullp_vma_nopage(struct vm_area_struct *vma, struct vm_fault *vmf) 61 | { 62 | unsigned long offset; 63 | struct scullp_dev *ptr, *dev = vma->vm_private_data; 64 | struct page *page = NULL; 65 | void *pageptr = NULL; /* default to "missing" */ 66 | int ret = 0; 67 | 68 | mutex_lock(&dev->mutex); 69 | offset = (unsigned long)(vmf->virtual_address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 70 | if (offset >= dev->size) goto out; /* out of range */ 71 | 72 | /* 73 | * Now retrieve the scullp device from the list,then the page. 74 | * If the device has holes, the process receives a SIGBUS when 75 | * accessing the hole. 76 | */ 77 | offset >>= PAGE_SHIFT; /* offset is a number of pages */ 78 | for (ptr = dev; ptr && offset >= dev->qset;) { 79 | ptr = ptr->next; 80 | offset -= dev->qset; 81 | } 82 | if (ptr && ptr->data) pageptr = ptr->data[offset]; 83 | if (!pageptr) { 84 | ret = VM_FAULT_SIGBUS; 85 | goto out; /* hole or end-of-file */ 86 | } 87 | page = virt_to_page(pageptr); 88 | 89 | /* got it, now increment the count */ 90 | get_page(page); 91 | vmf->page = page; 92 | 93 | out: 94 | mutex_unlock(&dev->mutex); 95 | return ret; 96 | } 97 | 98 | 99 | 100 | struct vm_operations_struct scullp_vm_ops = { 101 | .open = scullp_vma_open, 102 | .close = scullp_vma_close, 103 | .fault = scullp_vma_nopage, 104 | }; 105 | 106 | 107 | int scullp_mmap(struct file *filp, struct vm_area_struct *vma) 108 | { 109 | struct inode *inode = filp->f_dentry->d_inode; 110 | 111 | /* refuse to map if order is not 0 */ 112 | if (scullp_devices[iminor(inode)].order) 113 | return -ENODEV; 114 | 115 | /* don't do anything here: "nopage" will set up page table entries */ 116 | vma->vm_ops = &scullp_vm_ops; 117 | vma->vm_private_data = filp->private_data; 118 | scullp_vma_open(vma); 119 | return 0; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /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 | 19 | /* 20 | * Macros to help debugging 21 | */ 22 | 23 | #undef PDEBUG /* undef it, just in case */ 24 | #ifdef SCULLP_DEBUG 25 | # ifdef __KERNEL__ 26 | /* This one if debugging is on, and kernel space */ 27 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullp: " 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 SCULLP_MAJOR 0 /* dynamic major by default */ 40 | 41 | #define SCULLP_DEVS 4 /* scullp0 through scullp3 */ 42 | 43 | /* 44 | * The bare device is a variable-length region of memory. 45 | * Use a linked list of indirect blocks. 46 | * 47 | * "scullp_dev->data" points to an array of pointers, each 48 | * pointer refers to a memory page. 49 | * 50 | * The array (quantum-set) is SCULLP_QSET long. 51 | */ 52 | #define SCULLP_ORDER 0 /* one page at a time */ 53 | #define SCULLP_QSET 500 54 | 55 | struct scullp_dev { 56 | void **data; 57 | struct scullp_dev *next; /* next listitem */ 58 | int vmas; /* active mappings */ 59 | int order; /* the current allocation order */ 60 | int qset; /* the current array size */ 61 | size_t size; /* 32-bit will suffice */ 62 | struct mutex mutex; /* Mutual exclusion */ 63 | struct cdev cdev; 64 | }; 65 | 66 | extern struct scullp_dev *scullp_devices; 67 | 68 | extern struct file_operations scullp_fops; 69 | 70 | /* 71 | * The different configurable parameters 72 | */ 73 | extern int scullp_major; /* main.c */ 74 | extern int scullp_devs; 75 | extern int scullp_order; 76 | extern int scullp_qset; 77 | 78 | /* 79 | * Prototypes for shared functions 80 | */ 81 | int scullp_trim(struct scullp_dev *dev); 82 | struct scullp_dev *scullp_follow(struct scullp_dev *dev, int n); 83 | 84 | 85 | #ifdef SCULLP_DEBUG 86 | # define SCULLP_USE_PROC 87 | #endif 88 | 89 | /* 90 | * Ioctl definitions 91 | */ 92 | 93 | /* Use 'K' as magic number */ 94 | #define SCULLP_IOC_MAGIC 'K' 95 | 96 | #define SCULLP_IOCRESET _IO(SCULLP_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 SCULLP_IOCSORDER _IOW(SCULLP_IOC_MAGIC, 1, int) 107 | #define SCULLP_IOCTORDER _IO(SCULLP_IOC_MAGIC, 2) 108 | #define SCULLP_IOCGORDER _IOR(SCULLP_IOC_MAGIC, 3, int) 109 | #define SCULLP_IOCQORDER _IO(SCULLP_IOC_MAGIC, 4) 110 | #define SCULLP_IOCXORDER _IOWR(SCULLP_IOC_MAGIC, 5, int) 111 | #define SCULLP_IOCHORDER _IO(SCULLP_IOC_MAGIC, 6) 112 | #define SCULLP_IOCSQSET _IOW(SCULLP_IOC_MAGIC, 7, int) 113 | #define SCULLP_IOCTQSET _IO(SCULLP_IOC_MAGIC, 8) 114 | #define SCULLP_IOCGQSET _IOR(SCULLP_IOC_MAGIC, 9, int) 115 | #define SCULLP_IOCQQSET _IO(SCULLP_IOC_MAGIC, 10) 116 | #define SCULLP_IOCXQSET _IOWR(SCULLP_IOC_MAGIC,11, int) 117 | #define SCULLP_IOCHQSET _IO(SCULLP_IOC_MAGIC, 12) 118 | 119 | #define SCULLP_IOC_MAXNR 12 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /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 | /sbin/insmod -f ./$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 | /sbin/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 | # Comment/uncomment the following line to enable/disable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSCULLV_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I$(LDDINC) 13 | 14 | TARGET = scullv 15 | 16 | ifneq ($(KERNELRELEASE),) 17 | 18 | scullv-objs := main.o mmap.o 19 | 20 | obj-m := scullv.o 21 | 22 | else 23 | 24 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 25 | PWD := $(shell pwd) 26 | 27 | modules: 28 | $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD) modules 29 | 30 | endif 31 | 32 | 33 | install: 34 | install -d $(INSTALLDIR) 35 | install -c $(TARGET).o $(INSTALLDIR) 36 | 37 | clean: 38 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 39 | 40 | 41 | depend .depend dep: 42 | $(CC) -M *.c > .depend 43 | 44 | ifeq (.depend,$(wildcard .depend)) 45 | include .depend 46 | endif 47 | -------------------------------------------------------------------------------- /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 | 25 | #include "scullv.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 scullv_vma_open(struct vm_area_struct *vma) 34 | { 35 | struct scullv_dev *dev = vma->vm_private_data; 36 | 37 | dev->vmas++; 38 | } 39 | 40 | void scullv_vma_close(struct vm_area_struct *vma) 41 | { 42 | struct scullv_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 scullv 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 | 60 | int scullv_vma_nopage(struct vm_area_struct *vma, struct vm_fault *vmf) 61 | { 62 | unsigned long offset; 63 | struct scullv_dev *ptr, *dev = vma->vm_private_data; 64 | struct page *page = NULL; 65 | void *pageptr = NULL; /* default to "missing" */ 66 | int ret = 0; 67 | 68 | mutex_lock(&dev->mutex); 69 | offset = (unsigned long)(vmf->virtual_address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); 70 | if (offset >= dev->size) goto out; /* out of range */ 71 | 72 | /* 73 | * Now retrieve the scullv device from the list,then the page. 74 | * If the device has holes, the process receives a SIGBUS when 75 | * accessing the hole. 76 | */ 77 | offset >>= PAGE_SHIFT; /* offset is a number of pages */ 78 | for (ptr = dev; ptr && offset >= dev->qset;) { 79 | ptr = ptr->next; 80 | offset -= dev->qset; 81 | } 82 | if (ptr && ptr->data) pageptr = ptr->data[offset]; 83 | if (!pageptr) { 84 | ret = VM_FAULT_SIGBUS; 85 | goto out; /* hole or end-of-file */ 86 | } 87 | 88 | /* 89 | * After scullv lookup, "page" is now the address of the page 90 | * needed by the current process. Since it's a vmalloc address, 91 | * turn it into a struct page. 92 | */ 93 | page = vmalloc_to_page(pageptr); 94 | 95 | /* got it, now increment the count */ 96 | get_page(page); 97 | vmf->page = page; 98 | 99 | out: 100 | mutex_unlock(&dev->mutex); 101 | return ret; 102 | } 103 | 104 | 105 | 106 | struct vm_operations_struct scullv_vm_ops = { 107 | .open = scullv_vma_open, 108 | .close = scullv_vma_close, 109 | .fault = scullv_vma_nopage, 110 | }; 111 | 112 | 113 | int scullv_mmap(struct file *filp, struct vm_area_struct *vma) 114 | { 115 | 116 | /* don't do anything here: "nopage" will set up page table entries */ 117 | vma->vm_ops = &scullv_vm_ops; 118 | vma->vm_private_data = filp->private_data; 119 | scullv_vma_open(vma); 120 | return 0; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /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 | 19 | /* 20 | * Macros to help debugging 21 | */ 22 | 23 | #undef PDEBUG /* undef it, just in case */ 24 | #ifdef SCULLV_DEBUG 25 | # ifdef __KERNEL__ 26 | /* This one if debugging is on, and kernel space */ 27 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullv: " 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 SCULLV_MAJOR 0 /* dynamic major by default */ 40 | 41 | #define SCULLV_DEVS 4 /* scullv0 through scullv3 */ 42 | 43 | /* 44 | * The bare device is a variable-length region of memory. 45 | * Use a linked list of indirect blocks. 46 | * 47 | * "scullv_dev->data" points to an array of pointers, each 48 | * pointer refers to a memory page. 49 | * 50 | * The array (quantum-set) is SCULLV_QSET long. 51 | */ 52 | #define SCULLV_ORDER 4 /* 16 pages at a time */ 53 | #define SCULLV_QSET 500 54 | 55 | struct scullv_dev { 56 | void **data; 57 | struct scullv_dev *next; /* next listitem */ 58 | int vmas; /* active mappings */ 59 | int order; /* the current allocation order */ 60 | int qset; /* the current array size */ 61 | size_t size; /* 32-bit will suffice */ 62 | struct mutex mutex; /* Mutual exclusion */ 63 | struct cdev cdev; 64 | }; 65 | 66 | extern struct scullv_dev *scullv_devices; 67 | 68 | extern struct file_operations scullv_fops; 69 | 70 | /* 71 | * The different configurable parameters 72 | */ 73 | extern int scullv_major; /* main.c */ 74 | extern int scullv_devs; 75 | extern int scullv_order; 76 | extern int scullv_qset; 77 | 78 | /* 79 | * Prototypes for shared functions 80 | */ 81 | int scullv_trim(struct scullv_dev *dev); 82 | struct scullv_dev *scullv_follow(struct scullv_dev *dev, int n); 83 | 84 | 85 | #ifdef SCULLV_DEBUG 86 | # define SCULLV_USE_PROC 87 | #endif 88 | 89 | /* 90 | * Ioctl definitions 91 | */ 92 | 93 | /* Use 'K' as magic number */ 94 | #define SCULLV_IOC_MAGIC 'K' 95 | 96 | #define SCULLV_IOCRESET _IO(SCULLV_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 SCULLV_IOCSORDER _IOW(SCULLV_IOC_MAGIC, 1, int) 107 | #define SCULLV_IOCTORDER _IO(SCULLV_IOC_MAGIC, 2) 108 | #define SCULLV_IOCGORDER _IOR(SCULLV_IOC_MAGIC, 3, int) 109 | #define SCULLV_IOCQORDER _IO(SCULLV_IOC_MAGIC, 4) 110 | #define SCULLV_IOCXORDER _IOWR(SCULLV_IOC_MAGIC, 5, int) 111 | #define SCULLV_IOCHORDER _IO(SCULLV_IOC_MAGIC, 6) 112 | #define SCULLV_IOCSQSET _IOW(SCULLV_IOC_MAGIC, 7, int) 113 | #define SCULLV_IOCTQSET _IO(SCULLV_IOC_MAGIC, 8) 114 | #define SCULLV_IOCGQSET _IOR(SCULLV_IOC_MAGIC, 9, int) 115 | #define SCULLV_IOCQQSET _IO(SCULLV_IOC_MAGIC, 10) 116 | #define SCULLV_IOCXQSET _IOWR(SCULLV_IOC_MAGIC,11, int) 117 | #define SCULLV_IOCHQSET _IO(SCULLV_IOC_MAGIC, 12) 118 | 119 | #define SCULLV_IOC_MAXNR 12 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /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 | /sbin/insmod -f ./$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 | /sbin/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 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSHORT_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I.. 13 | 14 | ifneq ($(KERNELRELEASE),) 15 | # call from kernel build system 16 | 17 | obj-m := short.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 | clean: 31 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 32 | 33 | depend .depend dep: 34 | $(CC) -M *.c > .depend 35 | 36 | 37 | ifeq (.depend,$(wildcard .depend)) 38 | include .depend 39 | endif 40 | -------------------------------------------------------------------------------- /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 | /sbin/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 | /sbin/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 | ccflags-y += -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 24 | 25 | depend .depend dep: 26 | $(CC) -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 | /sbin/insmod -f ./$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 | /sbin/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 ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I$(LDDINCDIR) 13 | 14 | ifneq ($(KERNELRELEASE),) 15 | # call from kernel build system 16 | 17 | obj-m := simple.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) LDDINCDIR=$(PWD)/../include modules 26 | 27 | endif 28 | 29 | 30 | 31 | clean: 32 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 33 | 34 | depend .depend dep: 35 | $(CC) -M *.c > .depend 36 | 37 | 38 | ifeq (.depend,$(wildcard .depend)) 39 | include .depend 40 | endif 41 | -------------------------------------------------------------------------------- /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 | 32 | #include 33 | 34 | static int simple_major = 0; 35 | module_param(simple_major, int, 0); 36 | MODULE_AUTHOR("Jonathan Corbet"); 37 | MODULE_LICENSE("Dual BSD/GPL"); 38 | 39 | /* 40 | * Open the device; in fact, there's nothing to do here. 41 | */ 42 | int simple_open (struct inode *inode, struct file *filp) 43 | { 44 | return 0; 45 | } 46 | 47 | 48 | /* 49 | * Closing is just as simpler. 50 | */ 51 | int simple_release(struct inode *inode, struct file *filp) 52 | { 53 | return 0; 54 | } 55 | 56 | 57 | 58 | /* 59 | * Common VMA ops. 60 | */ 61 | 62 | void simple_vma_open(struct vm_area_struct *vma) 63 | { 64 | printk(KERN_NOTICE "Simple VMA open, virt %lx, phys %lx\n", 65 | vma->vm_start, vma->vm_pgoff << PAGE_SHIFT); 66 | } 67 | 68 | void simple_vma_close(struct vm_area_struct *vma) 69 | { 70 | printk(KERN_NOTICE "Simple VMA close.\n"); 71 | } 72 | 73 | 74 | /* 75 | * The remap_pfn_range version of mmap. This one is heavily borrowed 76 | * from drivers/char/mem.c. 77 | */ 78 | 79 | static struct vm_operations_struct simple_remap_vm_ops = { 80 | .open = simple_vma_open, 81 | .close = simple_vma_close, 82 | }; 83 | 84 | static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma) 85 | { 86 | if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 87 | vma->vm_end - vma->vm_start, 88 | vma->vm_page_prot)) 89 | return -EAGAIN; 90 | 91 | vma->vm_ops = &simple_remap_vm_ops; 92 | simple_vma_open(vma); 93 | return 0; 94 | } 95 | 96 | 97 | 98 | /* 99 | * The nopage version. 100 | */ 101 | static int simple_vma_nopage(struct vm_area_struct *vma, struct vm_fault *vmf) 102 | { 103 | struct page *pageptr; 104 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 105 | unsigned long physaddr = (unsigned long)vmf->virtual_address - vma->vm_start + offset; 106 | unsigned long pageframe = physaddr >> PAGE_SHIFT; 107 | 108 | // Eventually remove these printks 109 | printk (KERN_NOTICE "---- Nopage, off %lx phys %lx\n", offset, physaddr); 110 | printk (KERN_NOTICE "VA is %p\n", __va (physaddr)); 111 | printk (KERN_NOTICE "Page at %p\n", virt_to_page (__va (physaddr))); 112 | if (!pfn_valid(pageframe)) 113 | return VM_FAULT_SIGBUS; 114 | pageptr = pfn_to_page(pageframe); 115 | printk (KERN_NOTICE "page->index = %ld mapping %p\n", pageptr->index, pageptr->mapping); 116 | printk (KERN_NOTICE "Page frame %ld\n", pageframe); 117 | get_page(pageptr); 118 | 119 | vmf->page = pageptr; 120 | 121 | return 0; 122 | } 123 | 124 | static struct vm_operations_struct simple_nopage_vm_ops = { 125 | .open = simple_vma_open, 126 | .close = simple_vma_close, 127 | .fault = simple_vma_nopage, 128 | }; 129 | 130 | static int simple_nopage_mmap(struct file *filp, struct vm_area_struct *vma) 131 | { 132 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 133 | 134 | if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC)) 135 | vma->vm_flags |= VM_IO; 136 | 137 | vma->vm_ops = &simple_nopage_vm_ops; 138 | simple_vma_open(vma); 139 | return 0; 140 | } 141 | 142 | 143 | /* 144 | * Set up the cdev structure for a device. 145 | */ 146 | static void simple_setup_cdev(struct cdev *dev, int minor, 147 | struct file_operations *fops) 148 | { 149 | int err, devno = MKDEV(simple_major, minor); 150 | 151 | cdev_init(dev, fops); 152 | dev->owner = THIS_MODULE; 153 | dev->ops = fops; 154 | err = cdev_add (dev, devno, 1); 155 | /* Fail gracefully if need be */ 156 | if (err) 157 | printk (KERN_NOTICE "Error %d adding simple%d", err, minor); 158 | } 159 | 160 | 161 | /* 162 | * Our various sub-devices. 163 | */ 164 | /* Device 0 uses remap_pfn_range */ 165 | static struct file_operations simple_remap_ops = { 166 | .owner = THIS_MODULE, 167 | .open = simple_open, 168 | .release = simple_release, 169 | .mmap = simple_remap_mmap, 170 | }; 171 | 172 | /* Device 1 uses nopage */ 173 | static struct file_operations simple_nopage_ops = { 174 | .owner = THIS_MODULE, 175 | .open = simple_open, 176 | .release = simple_release, 177 | .mmap = simple_nopage_mmap, 178 | }; 179 | 180 | #define MAX_SIMPLE_DEV 2 181 | 182 | #if 0 183 | static struct file_operations *simple_fops[MAX_SIMPLE_DEV] = { 184 | &simple_remap_ops, 185 | &simple_nopage_ops, 186 | }; 187 | #endif 188 | 189 | /* 190 | * We export two simple devices. There's no need for us to maintain any 191 | * special housekeeping info, so we just deal with raw cdevs. 192 | */ 193 | static struct cdev SimpleDevs[MAX_SIMPLE_DEV]; 194 | 195 | /* 196 | * Module housekeeping. 197 | */ 198 | static int simple_init(void) 199 | { 200 | int result; 201 | dev_t dev = MKDEV(simple_major, 0); 202 | 203 | /* Figure out our device number. */ 204 | if (simple_major) 205 | result = register_chrdev_region(dev, 2, "simple"); 206 | else { 207 | result = alloc_chrdev_region(&dev, 0, 2, "simple"); 208 | simple_major = MAJOR(dev); 209 | } 210 | if (result < 0) { 211 | printk(KERN_WARNING "simple: unable to get major %d\n", simple_major); 212 | return result; 213 | } 214 | if (simple_major == 0) 215 | simple_major = result; 216 | 217 | /* Now set up two cdevs. */ 218 | simple_setup_cdev(SimpleDevs, 0, &simple_remap_ops); 219 | simple_setup_cdev(SimpleDevs + 1, 1, &simple_nopage_ops); 220 | return 0; 221 | } 222 | 223 | 224 | static void simple_cleanup(void) 225 | { 226 | cdev_del(SimpleDevs); 227 | cdev_del(SimpleDevs + 1); 228 | unregister_chrdev_region(MKDEV(simple_major, 0), 2); 229 | } 230 | 231 | 232 | module_init(simple_init); 233 | module_exit(simple_cleanup); 234 | -------------------------------------------------------------------------------- /simple/simple_load: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | module="simple" 3 | device="simple" 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 | # invoke insmod with all arguments we got 14 | # and use a pathname, as newer modutils don't look in . by default 15 | /sbin/insmod -f ./$module.ko $* || exit 1 16 | 17 | major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"` 18 | 19 | # Remove stale nodes and replace them, then give gid and perms 20 | # Usually the script is shorter, it's simple that has several devices in it. 21 | 22 | rm -f /dev/${device}[rn] 23 | mknod /dev/${device}r c $major 0 24 | mknod /dev/${device}n c $major 1 25 | chgrp $group /dev/${device}[rn] 26 | chmod $mode /dev/${device}[rn] 27 | -------------------------------------------------------------------------------- /simple/simple_unload: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | module="simple" 3 | device="simple" 4 | 5 | # invoke rmmod with all arguments we got 6 | /sbin/rmmod $module $* || exit 1 7 | 8 | # Remove stale nodes 9 | rm -f /dev/${device}[rn] 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /skull/Makefile: -------------------------------------------------------------------------------- 1 | foo: 2 | -------------------------------------------------------------------------------- /skull/skull_clean.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | void skull_release(unsigned int port, unsigned int range) 8 | { 9 | release_region(port,range); 10 | } 11 | 12 | void skull_cleanup(void) 13 | { 14 | /* should put real values here ... */ 15 | /* skull_release(0,0); */ 16 | } 17 | 18 | module_exit(skull_cleanup); 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /skull/skull_init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * skull.c -- sample typeless 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 | * BUGS: 16 | * -it only runs on intel platforms. 17 | * -readb() should be used (see short.c): skull doesn't work with 2.1 18 | * 19 | */ 20 | 21 | /* jc: cleaned up, but not yet run for anything */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include /* printk */ 29 | #include 30 | #include 31 | #include /* cli(), *_flags */ 32 | #include /* vremap (2.0) */ 33 | #include /* ioremap */ 34 | 35 | /* The region we look at. */ 36 | #define ISA_REGION_BEGIN 0xA0000 37 | #define ISA_REGION_END 0x100000 38 | #define STEP 2048 39 | 40 | /* have three symbols to export */ 41 | void skull_fn1(void){} 42 | static void skull_fn2(void){} 43 | int skull_variable; 44 | 45 | EXPORT_SYMBOL (skull_fn1); 46 | EXPORT_SYMBOL (skull_fn2); 47 | EXPORT_SYMBOL (skull_variable); 48 | 49 | 50 | /* perform hardware autodetection */ 51 | int skull_probe_hw(unsigned int port, unsigned int range) 52 | { 53 | /* do smart probing here */ 54 | return -1; /* not found :-) */ 55 | } 56 | 57 | /* perform hardware initalizazion */ 58 | int skull_init_board(unsigned int port) 59 | { 60 | /* do smart initalization here */ 61 | return 0; /* done :-) */ 62 | } 63 | 64 | /* detect the the device if the region is still free */ 65 | static int skull_detect(unsigned int port, unsigned int range) 66 | { 67 | int err; 68 | 69 | if ((err = check_region(port,range)) < 0) return err; /* busy */ 70 | if (skull_probe_hw(port,range) != 0) return -ENODEV; /* not found */ 71 | request_region(port,range,"skull"); /* "Can't fail" */ 72 | return 0; 73 | } 74 | 75 | /* 76 | * port ranges: the device can reside between 77 | * 0x280 and 0x300, in step of 0x10. It uses 0x10 ports. 78 | */ 79 | #define SKULL_PORT_FLOOR 0x280 80 | #define SKULL_PORT_CEIL 0x300 81 | #define SKULL_PORT_RANGE 0x010 82 | 83 | /* 84 | * the following function performs autodetection, unless a specific 85 | * value was assigned by insmod to "skull_port_base" 86 | */ 87 | 88 | static int skull_port_base=0; /* 0 forces autodetection */ 89 | module_param(skull_port_base, int, 0); 90 | 91 | static int skull_find_hw(void) /* returns the # of devices */ 92 | { 93 | /* base is either the load-time value or the first trial */ 94 | int base = skull_port_base ? skull_port_base 95 | : SKULL_PORT_FLOOR; 96 | int result = 0; 97 | 98 | /* loop one time if value assigned, try them all if autodetecting */ 99 | do { 100 | if (skull_detect(base, SKULL_PORT_RANGE) == 0) { 101 | skull_init_board(base); 102 | result++; 103 | } 104 | base += SKULL_PORT_RANGE; /* prepare for next trial */ 105 | } 106 | while (skull_port_base == 0 && base < SKULL_PORT_CEIL); 107 | 108 | return result; 109 | } 110 | 111 | 112 | int skull_init(void) 113 | { 114 | /* 115 | * Print the isa region map, in blocks of 2K bytes. 116 | * This is not the best code, as it prints too many lines, 117 | * but it deserves to remain short to be included in the book. 118 | * Note also that read() should be used instead of pointers. 119 | */ 120 | unsigned char oldval, newval; /* values read from memory */ 121 | unsigned long flags; /* used to hold system flags */ 122 | unsigned long add, i; 123 | void *base; 124 | 125 | /* Use ioremap to get a handle on our region */ 126 | base = ioremap(ISA_REGION_BEGIN, ISA_REGION_END - ISA_REGION_BEGIN); 127 | base -= ISA_REGION_BEGIN; /* Do the offset once */ 128 | 129 | /* probe all the memory hole in 2KB steps */ 130 | for (add = ISA_REGION_BEGIN; add < ISA_REGION_END; add += STEP) { 131 | /* 132 | * Check for an already allocated region. 133 | */ 134 | if (check_mem_region (add, 2048)) { 135 | printk(KERN_INFO "%lx: Allocated\n", add); 136 | continue; 137 | } 138 | /* 139 | * Read and write the beginning of the region and see what happens. 140 | */ 141 | save_flags(flags); 142 | cli(); 143 | oldval = readb (base + add); /* Read a byte */ 144 | writeb (oldval^0xff, base + add); 145 | mb(); 146 | newval = readb (base + add); 147 | writeb (oldval, base + add); 148 | restore_flags(flags); 149 | 150 | if ((oldval^newval) == 0xff) { /* we re-read our change: it's ram */ 151 | printk(KERN_INFO "%lx: RAM\n", add); 152 | continue; 153 | } 154 | if ((oldval^newval) != 0) { /* random bits changed: it's empty */ 155 | printk(KERN_INFO "%lx: empty\n", add); 156 | continue; 157 | } 158 | 159 | /* 160 | * Expansion rom (executed at boot time by the bios) 161 | * has a signature where the first byt is 0x55, the second 0xaa, 162 | * and the third byte indicates the size of such rom 163 | */ 164 | if ( (oldval == 0x55) && (readb (base + add + 1) == 0xaa)) { 165 | int size = 512 * readb (base + add + 2); 166 | printk(KERN_INFO "%lx: Expansion ROM, %i bytes\n", 167 | add, size); 168 | add += (size & ~2048) - 2048; /* skip it */ 169 | continue; 170 | } 171 | 172 | /* 173 | * If the tests above failed, we still don't know if it is ROM or 174 | * empty. Since empty memory can appear as 0x00, 0xff, or the low 175 | * address byte, we must probe multiple bytes: if at least one of 176 | * them is different from these three values, then this is rom 177 | * (though not boot rom). 178 | */ 179 | printk(KERN_INFO "%lx: ", add); 180 | for (i=0; i<5; i++) { 181 | unsigned long radd = add + 57*(i+1); /* a "random" value */ 182 | unsigned char val = readb (base + radd); 183 | if (val && val != 0xFF && val != ((unsigned long) radd&0xFF)) 184 | break; 185 | } 186 | printk("%s\n", i==5 ? "empty" : "ROM"); 187 | } 188 | 189 | /* 190 | * Find you hardware 191 | */ 192 | skull_find_hw(); 193 | 194 | /* 195 | * Always fail to load (or suceed). 196 | */ 197 | return 0; 198 | } 199 | 200 | module_init(skull_init); 201 | -------------------------------------------------------------------------------- /snull/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to disable/enable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSBULL_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I.. 13 | 14 | ifneq ($(KERNELRELEASE),) 15 | # call from kernel build system 16 | 17 | obj-m := snull.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 *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 33 | 34 | depend .depend dep: 35 | $(CC) -M *.c > .depend 36 | 37 | 38 | ifeq (.depend,$(wildcard .depend)) 39 | include .depend 40 | endif 41 | -------------------------------------------------------------------------------- /snull/snull.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * snull.h -- definitions for the network 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 | * Macros to help debugging 19 | */ 20 | 21 | #undef PDEBUG /* undef it, just in case */ 22 | #ifdef SNULL_DEBUG 23 | # ifdef __KERNEL__ 24 | /* This one if debugging is on, and kernel space */ 25 | # define PDEBUG(fmt, args...) printk( KERN_DEBUG "snull: " fmt, ## args) 26 | # else 27 | /* This one for user space */ 28 | # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args) 29 | # endif 30 | #else 31 | # define PDEBUG(fmt, args...) /* not debugging: nothing */ 32 | #endif 33 | 34 | #undef PDEBUGG 35 | #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */ 36 | 37 | 38 | /* These are the flags in the statusword */ 39 | #define SNULL_RX_INTR 0x0001 40 | #define SNULL_TX_INTR 0x0002 41 | 42 | /* Default timeout period */ 43 | #define SNULL_TIMEOUT 5 /* In jiffies */ 44 | 45 | extern struct net_device *snull_devs[]; 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /snull/snull_load: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export PATH=/sbin:/bin 4 | 5 | # Use a pathname, as new modutils don't look in the current dir by default 6 | insmod ./snull.ko $* 7 | ifconfig sn0 local0 8 | ifconfig sn1 local1 9 | -------------------------------------------------------------------------------- /snull/snull_unload: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /sbin/ifconfig sn0 down 4 | /sbin/ifconfig sn1 down 5 | /sbin/rmmod snull 6 | -------------------------------------------------------------------------------- /tty/Makefile: -------------------------------------------------------------------------------- 1 | # Comment/uncomment the following line to disable/enable debugging 2 | #DEBUG = y 3 | 4 | # Add your debugging flag (or not) to ccflags. 5 | ifeq ($(DEBUG),y) 6 | DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines 7 | else 8 | DEBFLAGS = -O2 9 | endif 10 | 11 | ccflags-y += $(DEBFLAGS) 12 | ccflags-y += -I.. 13 | 14 | ifneq ($(KERNELRELEASE),) 15 | # call from kernel build system 16 | 17 | obj-m := tiny_tty.o tiny_serial.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 *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 33 | 34 | depend .depend dep: 35 | $(CC) -M *.c > .depend 36 | 37 | 38 | ifeq (.depend,$(wildcard .depend)) 39 | include .depend 40 | endif 41 | -------------------------------------------------------------------------------- /tty/tiny_serial.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Tiny Serial driver 3 | * 4 | * Copyright (C) 2002-2004 Greg Kroah-Hartman (greg@kroah.com) 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, version 2 of the License. 9 | * 10 | * This driver shows how to create a minimal serial driver. It does not rely on 11 | * any backing hardware, but creates a timer that emulates data being received 12 | * from some kind of hardware. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | #define DRIVER_AUTHOR "Greg Kroah-Hartman " 27 | #define DRIVER_DESC "Tiny serial driver" 28 | 29 | /* Module information */ 30 | MODULE_AUTHOR( DRIVER_AUTHOR ); 31 | MODULE_DESCRIPTION( DRIVER_DESC ); 32 | MODULE_LICENSE("GPL"); 33 | 34 | #define DELAY_TIME HZ * 2 /* 2 seconds per character */ 35 | #define TINY_DATA_CHARACTER 't' 36 | 37 | #define TINY_SERIAL_MAJOR 240 /* experimental range */ 38 | #define TINY_SERIAL_MINORS 1 /* only have one minor */ 39 | #define UART_NR 1 /* only use one port */ 40 | 41 | #define TINY_SERIAL_NAME "ttytiny" 42 | 43 | #define MY_NAME TINY_SERIAL_NAME 44 | 45 | static struct timer_list *timer; 46 | 47 | static void tiny_stop_tx(struct uart_port *port, unsigned int tty_stop) 48 | { 49 | } 50 | 51 | static void tiny_stop_rx(struct uart_port *port) 52 | { 53 | } 54 | 55 | static void tiny_enable_ms(struct uart_port *port) 56 | { 57 | } 58 | 59 | static void tiny_tx_chars(struct uart_port *port) 60 | { 61 | struct circ_buf *xmit = &port->info->xmit; 62 | int count; 63 | 64 | if (port->x_char) { 65 | pr_debug("wrote %2x", port->x_char); 66 | port->icount.tx++; 67 | port->x_char = 0; 68 | return; 69 | } 70 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 71 | tiny_stop_tx(port, 0); 72 | return; 73 | } 74 | 75 | count = port->fifosize >> 1; 76 | do { 77 | pr_debug("wrote %2x", xmit->buf[xmit->tail]); 78 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 79 | port->icount.tx++; 80 | if (uart_circ_empty(xmit)) 81 | break; 82 | } while (--count > 0); 83 | 84 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 85 | uart_write_wakeup(port); 86 | 87 | if (uart_circ_empty(xmit)) 88 | tiny_stop_tx(port, 0); 89 | } 90 | 91 | static void tiny_start_tx(struct uart_port *port, unsigned int tty_start) 92 | { 93 | } 94 | 95 | static void tiny_timer(unsigned long data) 96 | { 97 | struct uart_port *port; 98 | struct tty_struct *tty; 99 | 100 | 101 | port = (struct uart_port *)data; 102 | if (!port) 103 | return; 104 | if (!port->info) 105 | return; 106 | tty = port->info->tty; 107 | if (!tty) 108 | return; 109 | 110 | /* add one character to the tty port */ 111 | /* this doesn't actually push the data through unless tty->low_latency is set */ 112 | tty_insert_flip_char(tty, TINY_DATA_CHARACTER, 0); 113 | 114 | tty_flip_buffer_push(tty); 115 | 116 | /* resubmit the timer again */ 117 | timer->expires = jiffies + DELAY_TIME; 118 | add_timer(timer); 119 | 120 | /* see if we have any data to transmit */ 121 | tiny_tx_chars(port); 122 | } 123 | 124 | static unsigned int tiny_tx_empty(struct uart_port *port) 125 | { 126 | return 0; 127 | } 128 | 129 | static unsigned int tiny_get_mctrl(struct uart_port *port) 130 | { 131 | return 0; 132 | } 133 | 134 | static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl) 135 | { 136 | } 137 | 138 | static void tiny_break_ctl(struct uart_port *port, int break_state) 139 | { 140 | } 141 | 142 | static void tiny_set_termios(struct uart_port *port, 143 | struct termios *new, struct termios *old) 144 | { 145 | int baud, quot, cflag = new->c_cflag; 146 | /* get the byte size */ 147 | switch (cflag & CSIZE) { 148 | case CS5: 149 | printk(KERN_DEBUG " - data bits = 5\n"); 150 | break; 151 | case CS6: 152 | printk(KERN_DEBUG " - data bits = 6\n"); 153 | break; 154 | case CS7: 155 | printk(KERN_DEBUG " - data bits = 7\n"); 156 | break; 157 | default: // CS8 158 | printk(KERN_DEBUG " - data bits = 8\n"); 159 | break; 160 | } 161 | 162 | /* determine the parity */ 163 | if (cflag & PARENB) 164 | if (cflag & PARODD) 165 | pr_debug(" - parity = odd\n"); 166 | else 167 | pr_debug(" - parity = even\n"); 168 | else 169 | pr_debug(" - parity = none\n"); 170 | 171 | /* figure out the stop bits requested */ 172 | if (cflag & CSTOPB) 173 | pr_debug(" - stop bits = 2\n"); 174 | else 175 | pr_debug(" - stop bits = 1\n"); 176 | 177 | /* figure out the flow control settings */ 178 | if (cflag & CRTSCTS) 179 | pr_debug(" - RTS/CTS is enabled\n"); 180 | else 181 | pr_debug(" - RTS/CTS is disabled\n"); 182 | 183 | /* Set baud rate */ 184 | baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); 185 | quot = uart_get_divisor(port, baud); 186 | 187 | //UART_PUT_DIV_LO(port, (quot & 0xff)); 188 | //UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8)); 189 | } 190 | 191 | static int tiny_startup(struct uart_port *port) 192 | { 193 | /* this is the first time this port is opened */ 194 | /* do any hardware initialization needed here */ 195 | 196 | /* create our timer and submit it */ 197 | if (!timer) { 198 | timer = kmalloc(sizeof(*timer), GFP_KERNEL); 199 | if (!timer) 200 | return -ENOMEM; 201 | } 202 | timer->data = (unsigned long)port; 203 | timer->expires = jiffies + DELAY_TIME; 204 | timer->function = tiny_timer; 205 | add_timer(timer); 206 | return 0; 207 | } 208 | 209 | static void tiny_shutdown(struct uart_port *port) 210 | { 211 | /* The port is being closed by the last user. */ 212 | /* Do any hardware specific stuff here */ 213 | 214 | /* shut down our timer */ 215 | del_timer(timer); 216 | } 217 | 218 | static const char *tiny_type(struct uart_port *port) 219 | { 220 | return "tinytty"; 221 | } 222 | 223 | static void tiny_release_port(struct uart_port *port) 224 | { 225 | 226 | } 227 | 228 | static int tiny_request_port(struct uart_port *port) 229 | { 230 | return 0; 231 | } 232 | 233 | static void tiny_config_port(struct uart_port *port, int flags) 234 | { 235 | } 236 | 237 | static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser) 238 | { 239 | return 0; 240 | } 241 | 242 | static struct uart_ops tiny_ops = { 243 | .tx_empty = tiny_tx_empty, 244 | .set_mctrl = tiny_set_mctrl, 245 | .get_mctrl = tiny_get_mctrl, 246 | .stop_tx = tiny_stop_tx, 247 | .start_tx = tiny_start_tx, 248 | .stop_rx = tiny_stop_rx, 249 | .enable_ms = tiny_enable_ms, 250 | .break_ctl = tiny_break_ctl, 251 | .startup = tiny_startup, 252 | .shutdown = tiny_shutdown, 253 | .set_termios = tiny_set_termios, 254 | .type = tiny_type, 255 | .release_port = tiny_release_port, 256 | .request_port = tiny_request_port, 257 | .config_port = tiny_config_port, 258 | .verify_port = tiny_verify_port, 259 | }; 260 | 261 | static struct uart_port tiny_port = { 262 | .ops = &tiny_ops, 263 | }; 264 | 265 | static struct uart_driver tiny_reg = { 266 | .owner = THIS_MODULE, 267 | .driver_name = TINY_SERIAL_NAME, 268 | .dev_name = TINY_SERIAL_NAME, 269 | .major = TINY_SERIAL_MAJOR, 270 | .minor = TINY_SERIAL_MINORS, 271 | .nr = UART_NR, 272 | }; 273 | 274 | static int __init tiny_init(void) 275 | { 276 | int result; 277 | 278 | printk(KERN_INFO "Tiny serial driver loaded\n"); 279 | 280 | result = uart_register_driver(&tiny_reg); 281 | if (result) 282 | return result; 283 | 284 | result = uart_add_one_port(&tiny_reg, &tiny_port); 285 | if (result) 286 | uart_unregister_driver(&tiny_reg); 287 | 288 | return result; 289 | } 290 | 291 | module_init(tiny_init); 292 | -------------------------------------------------------------------------------- /usb/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := usb-skeleton.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 11 | 12 | -------------------------------------------------------------------------------- /usb/usb-skeleton.c: -------------------------------------------------------------------------------- 1 | /* 2 | * USB Skeleton driver - 2.0 3 | * 4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License as 8 | * published by the Free Software Foundation, version 2. 9 | * 10 | * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c 11 | * but has been rewritten to be easy to read and use, as no locks are now 12 | * needed anymore. 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | /* Define these values to match your devices */ 29 | #define USB_SKEL_VENDOR_ID 0xfff0 30 | #define USB_SKEL_PRODUCT_ID 0xfff0 31 | 32 | /* table of devices that work with this driver */ 33 | static struct usb_device_id skel_table [] = { 34 | { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, 35 | { } /* Terminating entry */ 36 | }; 37 | MODULE_DEVICE_TABLE (usb, skel_table); 38 | 39 | 40 | /* Get a minor range for your devices from the usb maintainer */ 41 | #define USB_SKEL_MINOR_BASE 192 42 | 43 | /* Structure to hold all of our device specific stuff */ 44 | struct usb_skel { 45 | struct usb_device * udev; /* the usb device for this device */ 46 | struct usb_interface * interface; /* the interface for this device */ 47 | unsigned char * bulk_in_buffer; /* the buffer to receive data */ 48 | size_t bulk_in_size; /* the size of the receive buffer */ 49 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 50 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 51 | struct kref kref; 52 | }; 53 | #define to_skel_dev(d) container_of(d, struct usb_skel, kref) 54 | 55 | static struct usb_driver skel_driver; 56 | 57 | static void skel_delete(struct kref *kref) 58 | { 59 | struct usb_skel *dev = to_skel_dev(kref); 60 | 61 | usb_put_dev(dev->udev); 62 | kfree (dev->bulk_in_buffer); 63 | kfree (dev); 64 | } 65 | 66 | static int skel_open(struct inode *inode, struct file *file) 67 | { 68 | struct usb_skel *dev; 69 | struct usb_interface *interface; 70 | int subminor; 71 | int retval = 0; 72 | 73 | subminor = iminor(inode); 74 | 75 | interface = usb_find_interface(&skel_driver, subminor); 76 | if (!interface) { 77 | err ("%s - error, can't find device for minor %d", 78 | __FUNCTION__, subminor); 79 | retval = -ENODEV; 80 | goto exit; 81 | } 82 | 83 | dev = usb_get_intfdata(interface); 84 | if (!dev) { 85 | retval = -ENODEV; 86 | goto exit; 87 | } 88 | 89 | /* increment our usage count for the device */ 90 | kref_get(&dev->kref); 91 | 92 | /* save our object in the file's private structure */ 93 | file->private_data = dev; 94 | 95 | exit: 96 | return retval; 97 | } 98 | 99 | static int skel_release(struct inode *inode, struct file *file) 100 | { 101 | struct usb_skel *dev; 102 | 103 | dev = (struct usb_skel *)file->private_data; 104 | if (dev == NULL) 105 | return -ENODEV; 106 | 107 | /* decrement the count on our device */ 108 | kref_put(&dev->kref, skel_delete); 109 | return 0; 110 | } 111 | 112 | static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 113 | { 114 | struct usb_skel *dev; 115 | int retval = 0; 116 | 117 | dev = (struct usb_skel *)file->private_data; 118 | 119 | /* do a blocking bulk read to get data from the device */ 120 | retval = usb_bulk_msg(dev->udev, 121 | usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), 122 | dev->bulk_in_buffer, 123 | min(dev->bulk_in_size, count), 124 | &count, HZ*10); 125 | 126 | /* if the read was successful, copy the data to userspace */ 127 | if (!retval) { 128 | if (copy_to_user(buffer, dev->bulk_in_buffer, count)) 129 | retval = -EFAULT; 130 | else 131 | retval = count; 132 | } 133 | 134 | return retval; 135 | } 136 | 137 | static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) 138 | { 139 | /* sync/async unlink faults aren't errors */ 140 | if (urb->status && 141 | !(urb->status == -ENOENT || 142 | urb->status == -ECONNRESET || 143 | urb->status == -ESHUTDOWN)) { 144 | dbg("%s - nonzero write bulk status received: %d", 145 | __FUNCTION__, urb->status); 146 | } 147 | 148 | /* free up our allocated buffer */ 149 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, 150 | urb->transfer_buffer, urb->transfer_dma); 151 | } 152 | 153 | static ssize_t skel_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos) 154 | { 155 | struct usb_skel *dev; 156 | int retval = 0; 157 | struct urb *urb = NULL; 158 | char *buf = NULL; 159 | 160 | dev = (struct usb_skel *)file->private_data; 161 | 162 | /* verify that we actually have some data to write */ 163 | if (count == 0) 164 | goto exit; 165 | 166 | /* create a urb, and a buffer for it, and copy the data to the urb */ 167 | urb = usb_alloc_urb(0, GFP_KERNEL); 168 | if (!urb) { 169 | retval = -ENOMEM; 170 | goto error; 171 | } 172 | 173 | buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); 174 | if (!buf) { 175 | retval = -ENOMEM; 176 | goto error; 177 | } 178 | if (copy_from_user(buf, user_buffer, count)) { 179 | retval = -EFAULT; 180 | goto error; 181 | } 182 | 183 | /* initialize the urb properly */ 184 | usb_fill_bulk_urb(urb, dev->udev, 185 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 186 | buf, count, skel_write_bulk_callback, dev); 187 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 188 | 189 | /* send the data out the bulk port */ 190 | retval = usb_submit_urb(urb, GFP_KERNEL); 191 | if (retval) { 192 | err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); 193 | goto error; 194 | } 195 | 196 | /* release our reference to this urb, the USB core will eventually free it entirely */ 197 | usb_free_urb(urb); 198 | 199 | exit: 200 | return count; 201 | 202 | error: 203 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); 204 | usb_free_urb(urb); 205 | kfree(buf); 206 | return retval; 207 | } 208 | 209 | static struct file_operations skel_fops = { 210 | .owner = THIS_MODULE, 211 | .read = skel_read, 212 | .write = skel_write, 213 | .open = skel_open, 214 | .release = skel_release, 215 | }; 216 | 217 | /* 218 | * usb class driver info in order to get a minor number from the usb core, 219 | * and to have the device registered with devfs and the driver core 220 | */ 221 | static struct usb_class_driver skel_class = { 222 | .name = "usb/skel%d", 223 | .fops = &skel_fops, 224 | .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, 225 | .minor_base = USB_SKEL_MINOR_BASE, 226 | }; 227 | 228 | static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id) 229 | { 230 | struct usb_skel *dev = NULL; 231 | struct usb_host_interface *iface_desc; 232 | struct usb_endpoint_descriptor *endpoint; 233 | size_t buffer_size; 234 | int i; 235 | int retval = -ENOMEM; 236 | 237 | /* allocate memory for our device state and initialize it */ 238 | dev = kmalloc(sizeof(struct usb_skel), GFP_KERNEL); 239 | if (dev == NULL) { 240 | err("Out of memory"); 241 | goto error; 242 | } 243 | memset(dev, 0x00, sizeof (*dev)); 244 | kref_init(&dev->kref); 245 | 246 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); 247 | dev->interface = interface; 248 | 249 | /* set up the endpoint information */ 250 | /* use only the first bulk-in and bulk-out endpoints */ 251 | iface_desc = interface->cur_altsetting; 252 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 253 | endpoint = &iface_desc->endpoint[i].desc; 254 | 255 | if (!dev->bulk_in_endpointAddr && 256 | (endpoint->bEndpointAddress & USB_DIR_IN) && 257 | ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 258 | == USB_ENDPOINT_XFER_BULK)) { 259 | /* we found a bulk in endpoint */ 260 | buffer_size = endpoint->wMaxPacketSize; 261 | dev->bulk_in_size = buffer_size; 262 | dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; 263 | dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 264 | if (!dev->bulk_in_buffer) { 265 | err("Could not allocate bulk_in_buffer"); 266 | goto error; 267 | } 268 | } 269 | 270 | if (!dev->bulk_out_endpointAddr && 271 | !(endpoint->bEndpointAddress & USB_DIR_IN) && 272 | ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 273 | == USB_ENDPOINT_XFER_BULK)) { 274 | /* we found a bulk out endpoint */ 275 | dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; 276 | } 277 | } 278 | if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { 279 | err("Could not find both bulk-in and bulk-out endpoints"); 280 | goto error; 281 | } 282 | 283 | /* save our data pointer in this interface device */ 284 | usb_set_intfdata(interface, dev); 285 | 286 | /* we can register the device now, as it is ready */ 287 | retval = usb_register_dev(interface, &skel_class); 288 | if (retval) { 289 | /* something prevented us from registering this driver */ 290 | err("Not able to get a minor for this device."); 291 | usb_set_intfdata(interface, NULL); 292 | goto error; 293 | } 294 | 295 | /* let the user know what node this device is now attached to */ 296 | info("USB Skeleton device now attached to USBSkel-%d", interface->minor); 297 | return 0; 298 | 299 | error: 300 | if (dev) 301 | kref_put(&dev->kref, skel_delete); 302 | return retval; 303 | } 304 | 305 | static void skel_disconnect(struct usb_interface *interface) 306 | { 307 | struct usb_skel *dev; 308 | int minor = interface->minor; 309 | 310 | /* prevent skel_open() from racing skel_disconnect() */ 311 | lock_kernel(); 312 | 313 | dev = usb_get_intfdata(interface); 314 | usb_set_intfdata(interface, NULL); 315 | 316 | /* give back our minor */ 317 | usb_deregister_dev(interface, &skel_class); 318 | 319 | unlock_kernel(); 320 | 321 | /* decrement our usage count */ 322 | kref_put(&dev->kref, skel_delete); 323 | 324 | info("USB Skeleton #%d now disconnected", minor); 325 | } 326 | 327 | static struct usb_driver skel_driver = { 328 | .owner = THIS_MODULE, 329 | .name = "skeleton", 330 | .id_table = skel_table, 331 | .probe = skel_probe, 332 | .disconnect = skel_disconnect, 333 | }; 334 | 335 | static int __init usb_skel_init(void) 336 | { 337 | int result; 338 | 339 | /* register this driver with the USB subsystem */ 340 | result = usb_register(&skel_driver); 341 | if (result) 342 | err("usb_register failed. Error number %d", result); 343 | 344 | return result; 345 | } 346 | 347 | static void __exit usb_skel_exit(void) 348 | { 349 | /* deregister this driver with the USB subsystem */ 350 | usb_deregister(&skel_driver); 351 | } 352 | 353 | module_init (usb_skel_init); 354 | module_exit (usb_skel_exit); 355 | 356 | MODULE_LICENSE("GPL"); 357 | --------------------------------------------------------------------------------