summaryrefslogtreecommitdiffstats
path: root/misc-progs
diff options
context:
space:
mode:
authorJavier Martinez Canillas <martinez.javier@gmail.com>2010-11-27 07:49:17 +0100
committerJavier Martinez Canillas <martinez.javier@gmail.com>2010-11-27 07:49:17 +0100
commitab121f379a3cff458c90e6f480ba4bb68c8733dd (patch)
treea9851af109ee83646d108bc247d03b131461b764 /misc-progs
downloadldd3-ab121f379a3cff458c90e6f480ba4bb68c8733dd.tar.gz
Linux Device Drivers 3 examples
Diffstat (limited to 'misc-progs')
-rw-r--r--misc-progs/Makefile13
-rw-r--r--misc-progs/asynctest.c57
-rw-r--r--misc-progs/dataalign.c58
-rw-r--r--misc-progs/datasize.c35
-rw-r--r--misc-progs/gdbline19
-rw-r--r--misc-progs/inp.c129
-rw-r--r--misc-progs/load50.c38
-rw-r--r--misc-progs/mapcmp.c87
-rw-r--r--misc-progs/mapper.c71
-rw-r--r--misc-progs/nbtest.c44
-rw-r--r--misc-progs/netifdebug.c84
-rw-r--r--misc-progs/outp.c136
-rw-r--r--misc-progs/polltest.c47
-rw-r--r--misc-progs/setconsole.c42
-rw-r--r--misc-progs/setlevel.c47
15 files changed, 907 insertions, 0 deletions
diff --git a/misc-progs/Makefile b/misc-progs/Makefile
new file mode 100644
index 0000000..759ddec
--- /dev/null
+++ b/misc-progs/Makefile
@@ -0,0 +1,13 @@
+
+FILES = nbtest load50 mapcmp polltest mapper setlevel setconsole inp outp \
+ datasize dataalign netifdebug
+
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+INCLUDEDIR = $(KERNELDIR)/include
+CFLAGS = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR)
+
+all: $(FILES)
+
+clean:
+ rm -f $(FILES) *~ core
+
diff --git a/misc-progs/asynctest.c b/misc-progs/asynctest.c
new file mode 100644
index 0000000..8dcb458
--- /dev/null
+++ b/misc-progs/asynctest.c
@@ -0,0 +1,57 @@
+/*
+ * asynctest.c: use async notification to read stdin
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+
+int gotdata=0;
+void sighandler(int signo)
+{
+ if (signo==SIGIO)
+ gotdata++;
+ return;
+}
+
+char buffer[4096];
+
+int main(int argc, char **argv)
+{
+ int count;
+ struct sigaction action;
+
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = sighandler;
+ action.sa_flags = 0;
+
+ sigaction(SIGIO, &action, NULL);
+
+ fcntl(STDIN_FILENO, F_SETOWN, getpid());
+ fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);
+
+ while(1) {
+ /* this only returns if a signal arrives */
+ sleep(86400); /* one day */
+ if (!gotdata)
+ continue;
+ count=read(0, buffer, 4096);
+ /* buggy: if avail data is more than 4kbytes... */
+ write(1,buffer,count);
+ gotdata=0;
+ }
+}
diff --git a/misc-progs/dataalign.c b/misc-progs/dataalign.c
new file mode 100644
index 0000000..1042ab7
--- /dev/null
+++ b/misc-progs/dataalign.c
@@ -0,0 +1,58 @@
+/*
+ * dataalign.c -- show alignment needs
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ *
+ * This runs with any Linux kernel (not any Unix, because of <linux/types.h>)
+ */
+#include <stdio.h>
+#include <sys/utsname.h>
+#include <linux/types.h>
+
+/*
+ * Define several data structures, all of them start with a lone char
+ * in order to present an unaligned offset for the next field
+ */
+struct c {char c; char t;} c;
+struct s {char c; short t;} s;
+struct i {char c; int t;} i;
+struct l {char c; long t;} l;
+struct ll {char c; long long t;} ll;
+struct p {char c; void * t;} p;
+struct u1b {char c; __u8 t;} u1b;
+struct u2b {char c; __u16 t;} u2b;
+struct u4b {char c; __u32 t;} u4b;
+struct u8b {char c; __u64 t;} u8b;
+
+int main(int argc, char **argv)
+{
+ struct utsname name;
+
+ uname(&name); /* never fails :) */
+ printf("arch Align: char short int long ptr long-long "
+ " u8 u16 u32 u64\n");
+ printf( "%-12s %3i %3i %3i %3i %3i %3i "
+ "%3i %3i %3i %3i\n",
+ name.machine,
+ /* note that gcc can subtract void * values, but it's not ansi */
+ (int)((void *)(&c.t) - (void *)&c),
+ (int)((void *)(&s.t) - (void *)&s),
+ (int)((void *)(&i.t) - (void *)&i),
+ (int)((void *)(&l.t) - (void *)&l),
+ (int)((void *)(&p.t) - (void *)&p),
+ (int)((void *)(&ll.t) - (void *)&ll),
+ (int)((void *)(&u1b.t) - (void *)&u1b),
+ (int)((void *)(&u2b.t) - (void *)&u2b),
+ (int)((void *)(&u4b.t) - (void *)&u4b),
+ (int)((void *)(&u8b.t) - (void *)&u8b));
+ return 0;
+}
diff --git a/misc-progs/datasize.c b/misc-progs/datasize.c
new file mode 100644
index 0000000..bf63423
--- /dev/null
+++ b/misc-progs/datasize.c
@@ -0,0 +1,35 @@
+/*
+ * datasize.c -- print the size of common data items
+ * This runs with any Linux kernel (not any Unix, because of <linux/types.h>)
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ */
+#include <stdio.h>
+#include <sys/utsname.h>
+#include <linux/types.h>
+
+int main(int argc, char **argv)
+{
+ struct utsname name;
+
+ uname(&name); /* never fails :) */
+ printf("arch Size: char short int long ptr long-long "
+ " u8 u16 u32 u64\n");
+ printf( "%-12s %3i %3i %3i %3i %3i %3i "
+ "%3i %3i %3i %3i\n",
+ name.machine,
+ (int)sizeof(char), (int)sizeof(short), (int)sizeof(int),
+ (int)sizeof(long),
+ (int)sizeof(void *), (int)sizeof(long long), (int)sizeof(__u8),
+ (int)sizeof(__u16), (int)sizeof(__u32), (int)sizeof(__u64));
+ return 0;
+}
diff --git a/misc-progs/gdbline b/misc-progs/gdbline
new file mode 100644
index 0000000..d66572e
--- /dev/null
+++ b/misc-progs/gdbline
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# $Id: gdbline,v 1.1 2004/08/02 16:27:55 corbet Exp $
+#
+# gdbline module image
+#
+# Outputs an add-symbol-file line suitable for pasting into gdb to examine
+# a loaded module.
+#
+cd /sys/module/$1/sections
+echo -n add-symbol-file $2 `/bin/cat .text`
+
+for section in .[a-z]* *; do
+ if [ $section != ".text" ]; then
+ echo " \\"
+ echo -n " -s" $section `/bin/cat $section`
+ fi
+done
+echo
diff --git a/misc-progs/inp.c b/misc-progs/inp.c
new file mode 100644
index 0000000..282d570
--- /dev/null
+++ b/misc-progs/inp.c
@@ -0,0 +1,129 @@
+/*
+ * inp.c -- read all the ports specified in hex on the command line.
+ * The program uses the faster ioperm/iopl calls on x86, /dev/port
+ * on other platforms. The program acts as inb/inw/inl according
+ * to its own name
+ *
+ * Copyright (C) 1998,2000,2001 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/io.h> /* linux-specific */
+
+#ifdef __GLIBC__
+# include <sys/perm.h>
+#endif
+
+#define PORT_FILE "/dev/port"
+
+char *prgname;
+
+#ifdef __i386__
+static int read_and_print_one(unsigned int port,int size)
+{
+ static int iopldone = 0;
+
+ if (port > 1024) {
+ if (!iopldone && iopl(3)) {
+ fprintf(stderr, "%s: iopl(): %s\n", prgname, strerror(errno));
+ return 1;
+ }
+ iopldone++;
+ } else if (ioperm(port,size,1)) {
+ fprintf(stderr, "%s: ioperm(%x): %s\n", prgname,
+ port, strerror(errno));
+ return 1;
+ }
+
+ if (size == 4)
+ printf("%04x: %08x\n", port, inl(port));
+ else if (size == 2)
+ printf("%04x: %04x\n", port, inw(port));
+ else
+ printf("%04x: %02x\n", port, inb(port));
+ return 0;
+}
+#else /* not i386 */
+
+static int read_and_print_one(unsigned int port,int size)
+{
+ static int fd = -1;
+ unsigned char b; unsigned short w; unsigned int l;
+
+ if (fd < 0)
+ fd = open(PORT_FILE, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "%s: %s: %s\n", prgname, PORT_FILE, strerror(errno));
+ return 1;
+ }
+ lseek(fd, port, SEEK_SET);
+
+ if (size == 4) {
+ read(fd, &l, 4);
+ printf("%04x: 0x%08x\n", port, l);
+ } else if (size == 2) {
+ read(fd, &w, 2);
+ printf("%04x: 0x%04x\n", port, w & 0xffff);
+ } else {
+ read(fd, &b, 1);
+ printf("%04x: 0x%02x\n", port, b & 0xff);
+ }
+ return 0;
+}
+
+#endif /* i386 */
+
+
+int main(int argc, char **argv)
+{
+ unsigned int i, n, port, size, error = 0;
+
+ prgname = argv[0];
+ /* find the data size */
+ switch (prgname[strlen(prgname)-1]) {
+ case 'w': size = 2; break;
+ case 'l': size = 4; break;
+ case 'b': case 'p': default:
+ size = 1;
+ }
+
+ setuid(0); /* if we're setuid, force it on */
+ for (i = 1; i < argc; i++) {
+ if ( sscanf(argv[i], "%x%n", &port, &n) < 1
+ || n != strlen(argv[i]) ) {
+ fprintf(stderr, "%s: argument \"%s\" is not a hex number\n",
+ argv[0], argv[i]);
+ error++; continue;
+ }
+ if (port & (size-1)) {
+ fprintf(stderr, "%s: argument \"%s\" is not properly aligned\n",
+ argv[0], argv[i]);
+ error++; continue;
+ }
+ error += read_and_print_one(port, size);
+ }
+ exit (error ? 1 : 0);
+}
+
diff --git a/misc-progs/load50.c b/misc-progs/load50.c
new file mode 100644
index 0000000..f9d93a0
--- /dev/null
+++ b/misc-progs/load50.c
@@ -0,0 +1,38 @@
+/*
+ * load50.c -- a simple busy-looping tool.
+ * Obviously, this runs with any kernel and any Unix
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ int i, load=50;
+
+ if (argc==2) {
+ load=atoi(argv[1]);
+ }
+ printf("Bringing load to %i\n",load);
+
+ for (i=0; i<load; i++)
+ if (fork()==0)
+ break;
+
+ while(1)
+ ;
+ return 0;
+}
+
diff --git a/misc-progs/mapcmp.c b/misc-progs/mapcmp.c
new file mode 100644
index 0000000..8ef8831
--- /dev/null
+++ b/misc-progs/mapcmp.c
@@ -0,0 +1,87 @@
+/*
+ * Simple program to compare two mmap'd areas.
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ *
+ * $Id: mapcmp.c,v 1.2 2004/03/05 17:35:41 corbet Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <fcntl.h>
+
+static char *mapdev (const char *, unsigned long, unsigned long);
+#define PAGE_SIZE 4096
+
+/*
+ * memcmp dev1 dev2 offset pages
+ */
+int main (int argc, char **argv)
+{
+ unsigned long offset, size, i;
+ char *addr1, *addr2;
+/*
+ * Sanity check.
+ */
+ if (argc != 5)
+ {
+ fprintf (stderr, "Usage: mapcmp dev1 dev2 offset pages\n");
+ exit (1);
+ }
+/*
+ * Map the two devices.
+ */
+ offset = strtoul (argv[3], NULL, 16);
+ size = atoi (argv[4])*PAGE_SIZE;
+ printf ("Offset is 0x%lx\n", offset);
+ addr1 = mapdev (argv[1], offset, size);
+ addr2 = mapdev (argv[2], offset, size);
+/*
+ * Do the comparison.
+ */
+ printf ("Comparing...");
+ fflush (stdout);
+ for (i = 0; i < size; i++)
+ if (*addr1++ != *addr2++)
+ {
+ printf ("areas differ at byte %ld\n", i);
+ exit (0);
+ }
+ printf ("areas are identical.\n");
+ exit (0);
+}
+
+
+
+static char *mapdev (const char *dev, unsigned long offset,
+ unsigned long size)
+{
+ char *addr;
+ int fd = open (dev, O_RDONLY);
+
+ if (fd < 0)
+ {
+ perror (dev);
+ exit (1);
+ }
+ addr = mmap (0, size, PROT_READ, MAP_PRIVATE, fd, offset);
+ if (addr == MAP_FAILED)
+ {
+ perror (dev);
+ exit (1);
+ }
+ printf ("Mapped %s (%lu @ %lx) at %p\n", dev, size, offset, addr);
+ return (addr);
+}
diff --git a/misc-progs/mapper.c b/misc-progs/mapper.c
new file mode 100644
index 0000000..ae8db09
--- /dev/null
+++ b/misc-progs/mapper.c
@@ -0,0 +1,71 @@
+/*
+ * mapper.c -- simple file that mmap()s a file region and prints it
+ *
+ * Copyright (C) 1998,2000,2001 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <limits.h>
+
+int main(int argc, char **argv)
+{
+ char *fname;
+ FILE *f;
+ unsigned long offset, len;
+ void *address;
+
+ if (argc !=4
+ || sscanf(argv[2],"%li", &offset) != 1
+ || sscanf(argv[3],"%li", &len) != 1) {
+ fprintf(stderr, "%s: Usage \"%s <file> <offset> <len>\"\n", argv[0],
+ argv[0]);
+ exit(1);
+ }
+ /* the offset might be big (e.g., PCI devices), but conversion trims it */
+ if (offset == INT_MAX) {
+ if (argv[2][1]=='x')
+ sscanf(argv[2]+2, "%lx", &offset);
+ else
+ sscanf(argv[2], "%lu", &offset);
+ }
+
+ fname=argv[1];
+
+ if (!(f=fopen(fname,"r"))) {
+ fprintf(stderr, "%s: %s: %s\n", argv[0], fname, strerror(errno));
+ exit(1);
+ }
+
+ address=mmap(0, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fileno(f), offset);
+
+ if (address == (void *)-1) {
+ fprintf(stderr,"%s: mmap(): %s\n",argv[0],strerror(errno));
+ exit(1);
+ }
+ fclose(f);
+ fprintf(stderr, "mapped \"%s\" from %lu (0x%08lx) to %lu (0x%08lx)\n",
+ fname, offset, offset, offset+len, offset+len);
+
+ fwrite(address, 1, len, stdout);
+ return 0;
+}
+
diff --git a/misc-progs/nbtest.c b/misc-progs/nbtest.c
new file mode 100644
index 0000000..6a0bd54
--- /dev/null
+++ b/misc-progs/nbtest.c
@@ -0,0 +1,44 @@
+/*
+ * nbtest.c: read and write in non-blocking mode
+ * This should run with any Unix
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+
+char buffer[4096];
+
+int main(int argc, char **argv)
+{
+ int delay = 1, n, m = 0;
+
+ if (argc > 1)
+ delay=atoi(argv[1]);
+ fcntl(0, F_SETFL, fcntl(0,F_GETFL) | O_NONBLOCK); /* stdin */
+ fcntl(1, F_SETFL, fcntl(1,F_GETFL) | O_NONBLOCK); /* stdout */
+
+ while (1) {
+ n = read(0, buffer, 4096);
+ if (n >= 0)
+ m = write(1, buffer, n);
+ if ((n < 0 || m < 0) && (errno != EAGAIN))
+ break;
+ sleep(delay);
+ }
+ perror(n < 0 ? "stdin" : "stdout");
+ exit(1);
+}
diff --git a/misc-progs/netifdebug.c b/misc-progs/netifdebug.c
new file mode 100644
index 0000000..6f0ce75
--- /dev/null
+++ b/misc-progs/netifdebug.c
@@ -0,0 +1,84 @@
+/*
+ * netifdebug.c -- change the IFF_DEBUG flag of an interface
+ *
+ * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2001 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+int main(int argc, char **argv)
+{
+ int action = -1, sock;
+ struct ifreq req;
+ char *actname;
+
+ if (argc < 2) {
+ fprintf(stderr,"%s: usage is \"%s <ifname> [<on|off|tell>]\"\n",
+ argv[0],argv[0]);
+ exit(1);
+ }
+ if (argc==2)
+ actname="tell";
+ else
+ actname=argv[2];
+
+ /* a silly raw socket just for ioctl()ling it */
+ sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (sock < 0) {
+ fprintf(stderr, "%s: socket(): %s\n", argv[0],strerror(errno));
+ exit(1);
+ }
+
+ /* retrieve flags */
+ strcpy(req.ifr_name, argv[1]);
+ if ( ioctl(sock, SIOCGIFFLAGS, &req) < 0) {
+ fprintf(stderr, " %s: ioctl(SIOCGIFFLAGS): %s\n",
+ argv[0],strerror(errno));
+ exit(1);
+ }
+
+ if (!strcmp(actname,"on")
+ || !strcmp(actname,"+")
+ || !strcmp(actname,"1"))
+ action = IFF_DEBUG;
+
+ if (!strcmp(actname,"off")
+ || !strcmp(actname,"-")
+ || !strcmp(actname,"0"))
+ action = 0;
+
+ if (!strcmp(actname,"tell")
+ || actname[0]=='t') {
+ printf("%s: debug is %s\n", argv[1],
+ req.ifr_flags & IFF_DEBUG ? "on" : "off");
+ exit(0);
+ }
+
+ req.ifr_flags &= ~IFF_DEBUG;
+ req.ifr_flags |= action;
+
+ if ( ioctl(sock, SIOCSIFFLAGS, &req) < 0) {
+ fprintf(stderr, " %s: ioctl(SIOCSIFFLAGS): %s\n",
+ argv[0],strerror(errno));
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/misc-progs/outp.c b/misc-progs/outp.c
new file mode 100644
index 0000000..219d613
--- /dev/null
+++ b/misc-progs/outp.c
@@ -0,0 +1,136 @@
+/*
+ * outp.c -- write all the ports specified in hex on the command line.
+ * The program uses the faster ioperm/iopl calls on x86, /dev/port
+ * on other platforms. The program acts as outb/outw/outl according
+ * to its own name
+ *
+ * Copyright (C) 1998,2000,2001 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/io.h> /* linux-specific */
+
+#ifdef __GLIBC__
+# include <sys/perm.h>
+#endif
+
+#define PORT_FILE "/dev/port"
+
+char *prgname;
+
+#ifdef __i386__
+static int write_one(unsigned int port, unsigned int val, int size)
+{
+ static int iopldone = 0;
+
+ if (port > 1024) {
+ if (!iopldone && iopl(3)) {
+ fprintf(stderr, "%s: iopl(): %s\n", prgname, strerror(errno));
+ return 1;
+ }
+ iopldone++;
+ } else if (ioperm(port,size,1)) {
+ fprintf(stderr, "%s: ioperm(%x): %s\n", prgname,
+ port, strerror(errno));
+ return 1;
+ }
+
+ if (size == 4)
+ outl(val, port);
+ else if (size == 2)
+ outw(val&0xffff, port);
+ else
+ outb(val&0xff, port);
+ return 0;
+}
+#else /* not i386 */
+
+static int write_one(unsigned int port, unsigned int val, int size)
+{
+ static int fd = -1;
+ unsigned char b; unsigned short w;
+
+ if (fd < 0)
+ fd = open(PORT_FILE, O_WRONLY);
+ if (fd < 0) {
+ fprintf(stderr, "%s: %s: %s\n", prgname, PORT_FILE, strerror(errno));
+ return 1;
+ }
+ lseek(fd, port, SEEK_SET);
+
+ if (size == 4) {
+ write(fd, &val, 4);
+ } else if (size == 2) {
+ w = val;
+ write(fd, &w, 2);
+ } else {
+ b = val;
+ write(fd, &b, 1);
+ }
+ return 0;
+}
+
+#endif /* i386 */
+
+int main(int argc, char **argv)
+{
+ unsigned int i, n, port, val, size, error = 0;
+
+ prgname = argv[0];
+ /* find the data size */
+ switch (prgname[strlen(prgname)-1]) {
+ case 'w': size = 2; break;
+ case 'l': size = 4; break;
+ case 'b': case 'p': default:
+ size = 1;
+ }
+ setuid(0); /* if we're setuid, force it on */
+ for (i=1;i<argc-1;i++) {
+ if ( sscanf(argv[i], "%x%n", &port, &n) < 1
+ || n != strlen(argv[i]) ) {
+ fprintf(stderr, "%s: argument \"%s\" is not a hex number\n",
+ argv[0], argv[i]);
+ error++; continue;
+ }
+ if (port & (size-1)) {
+ fprintf(stderr, "%s: argument \"%s\" is not properly aligned\n",
+ argv[0], argv[i]);
+ error++; continue;
+ }
+ if ( sscanf(argv[i+1], "%x%n", &val, &n) < 1
+ || n != strlen(argv[i+1]) ) {
+ fprintf(stderr, "%s: argument \"%s\" is not a hex number\n",
+ argv[0], argv[i+1]);
+ error++; continue;
+ }
+ if (size < 4 && val > (size == 1 ? 0xff : 0xffff)) {
+ fprintf(stderr, "%s: argument \"%s\" out of range\n",
+ argv[0], argv[i+1]);
+ error++; continue;
+ }
+ error += write_one(port, val, size);
+ }
+ exit (error ? 1 : 0);
+}
diff --git a/misc-progs/polltest.c b/misc-progs/polltest.c
new file mode 100644
index 0000000..fdc461d
--- /dev/null
+++ b/misc-progs/polltest.c
@@ -0,0 +1,47 @@
+/*
+ * Test out reading with poll()
+ * This should run with any Unix
+ *
+ * Copyright (C) 2003 Alessandro Rubini and Jonathan Corbet
+ * Copyright (C) 2003 O'Reilly & Associates
+ *
+ * The source code in this file can be freely used, adapted,
+ * and redistributed in source or binary form, so long as an
+ * acknowledgment appears in derived source files. The citation
+ * should list that the code comes from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates. No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ *
+ * $Id: polltest.c,v 1.1 2003/02/07 18:01:38 corbet Exp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+
+char buffer[4096];
+
+int main(int argc, char **argv)
+{
+ struct pollfd pfd;
+ int n;
+
+ fcntl(0, F_SETFL, fcntl(0,F_GETFL) | O_NONBLOCK); /* stdin */
+ pfd.fd = 0; /* stdin */
+ pfd.events = POLLIN;
+
+ while (1) {
+ n=read(0, buffer, 4096);
+ if (n >= 0)
+ write(1, buffer, n);
+ n = poll(&pfd, 1, -1);
+ if (n < 0)
+ break;
+ }
+ perror( n<0 ? "stdin" : "stdout");
+ exit(1);
+}
diff --git a/misc-progs/setconsole.c b/misc-progs/setconsole.c
new file mode 100644
index 0000000..04bc11d
--- /dev/null
+++ b/misc-progs/setconsole.c
@@ -0,0 +1,42 @@
+/*
+ * setconsole.c -- choose a console to receive kernel messages
+ *
+ * Copyright (C) 1998,2000,2001 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+int main(int argc, char **argv)
+{
+ char bytes[2] = {11,0}; /* 11 is the TIOCLINUX cmd number */
+
+ if (argc==2) bytes[1] = atoi(argv[1]); /* the chosen console */
+ else {
+ fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
+ }
+ if (ioctl(STDIN_FILENO, TIOCLINUX, bytes)<0) { /* use stdin */
+ fprintf(stderr,"%s: ioctl(stdin, TIOCLINUX): %s\n",
+ argv[0], strerror(errno));
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/misc-progs/setlevel.c b/misc-progs/setlevel.c
new file mode 100644
index 0000000..fec666d
--- /dev/null
+++ b/misc-progs/setlevel.c
@@ -0,0 +1,47 @@
+/*
+ * setlevel.c -- choose a console_loglevel for the kernel
+ *
+ * Copyright (C) 1998,2000,2001 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+/* #include <unistd.h> */ /* conflicting on the alpha */
+#define __LIBRARY__ /* _syscall3 and friends are only available through this */
+#include <linux/unistd.h>
+
+/* define the system call, to override the library function */
+_syscall3(int, syslog, int, type, char *, bufp, int, len);
+
+int main(int argc, char **argv)
+{
+ int level;
+
+ if (argc==2) {
+ level = atoi(argv[1]); /* the chosen console */
+ } else {
+ fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
+ }
+ if (syslog(8,NULL,level) < 0) {
+ fprintf(stderr,"%s: syslog(setlevel): %s\n",
+ argv[0],strerror(errno));
+ exit(1);
+ }
+ exit(0);
+}