diff options
author | Javier Martinez Canillas <martinez.javier@gmail.com> | 2010-11-27 07:49:17 +0100 |
---|---|---|
committer | Javier Martinez Canillas <martinez.javier@gmail.com> | 2010-11-27 07:49:17 +0100 |
commit | ab121f379a3cff458c90e6f480ba4bb68c8733dd (patch) | |
tree | a9851af109ee83646d108bc247d03b131461b764 /misc-progs | |
download | ldd3-ab121f379a3cff458c90e6f480ba4bb68c8733dd.tar.gz |
Linux Device Drivers 3 examples
Diffstat (limited to 'misc-progs')
-rw-r--r-- | misc-progs/Makefile | 13 | ||||
-rw-r--r-- | misc-progs/asynctest.c | 57 | ||||
-rw-r--r-- | misc-progs/dataalign.c | 58 | ||||
-rw-r--r-- | misc-progs/datasize.c | 35 | ||||
-rw-r--r-- | misc-progs/gdbline | 19 | ||||
-rw-r--r-- | misc-progs/inp.c | 129 | ||||
-rw-r--r-- | misc-progs/load50.c | 38 | ||||
-rw-r--r-- | misc-progs/mapcmp.c | 87 | ||||
-rw-r--r-- | misc-progs/mapper.c | 71 | ||||
-rw-r--r-- | misc-progs/nbtest.c | 44 | ||||
-rw-r--r-- | misc-progs/netifdebug.c | 84 | ||||
-rw-r--r-- | misc-progs/outp.c | 136 | ||||
-rw-r--r-- | misc-progs/polltest.c | 47 | ||||
-rw-r--r-- | misc-progs/setconsole.c | 42 | ||||
-rw-r--r-- | misc-progs/setlevel.c | 47 |
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); +} |