From ab121f379a3cff458c90e6f480ba4bb68c8733dd Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 27 Nov 2010 07:49:17 +0100 Subject: Linux Device Drivers 3 examples --- skull/Makefile | 1 + skull/skull_clean.c | 22 ++++++ skull/skull_init.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 skull/Makefile create mode 100644 skull/skull_clean.c create mode 100644 skull/skull_init.c (limited to 'skull') diff --git a/skull/Makefile b/skull/Makefile new file mode 100644 index 0000000..0152a79 --- /dev/null +++ b/skull/Makefile @@ -0,0 +1 @@ +foo: diff --git a/skull/skull_clean.c b/skull/skull_clean.c new file mode 100644 index 0000000..9d1e789 --- /dev/null +++ b/skull/skull_clean.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#include + +void skull_release(unsigned int port, unsigned int range) +{ + release_region(port,range); +} + +void skull_cleanup(void) +{ + /* should put real values here ... */ + /* skull_release(0,0); */ +} + +module_exit(skull_cleanup); + + + + diff --git a/skull/skull_init.c b/skull/skull_init.c new file mode 100644 index 0000000..aaa06e2 --- /dev/null +++ b/skull/skull_init.c @@ -0,0 +1,200 @@ +/* + * skull.c -- sample typeless module. + * + * 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. + * + * BUGS: + * -it only runs on intel platforms. + * -readb() should be used (see short.c): skull doesn't work with 2.1 + * + */ + +/* jc: cleaned up, but not yet run for anything */ + +#include +#include +#include +#include + +#include /* printk */ +#include +#include +#include /* cli(), *_flags */ +#include /* vremap (2.0) */ +#include /* ioremap */ + +/* The region we look at. */ +#define ISA_REGION_BEGIN 0xA0000 +#define ISA_REGION_END 0x100000 +#define STEP 2048 + +/* have three symbols to export */ + void skull_fn1(void){} +static void skull_fn2(void){} + int skull_variable; + +EXPORT_SYMBOL (skull_fn1); +EXPORT_SYMBOL (skull_fn2); +EXPORT_SYMBOL (skull_variable); + + +/* perform hardware autodetection */ +int skull_probe_hw(unsigned int port, unsigned int range) +{ + /* do smart probing here */ + return -1; /* not found :-) */ +} + +/* perform hardware initalizazion */ +int skull_init_board(unsigned int port) +{ + /* do smart initalization here */ + return 0; /* done :-) */ +} + +/* detect the the device if the region is still free */ +static int skull_detect(unsigned int port, unsigned int range) +{ + int err; + + if ((err = check_region(port,range)) < 0) return err; /* busy */ + if (skull_probe_hw(port,range) != 0) return -ENODEV; /* not found */ + request_region(port,range,"skull"); /* "Can't fail" */ + return 0; +} + +/* + * port ranges: the device can reside between + * 0x280 and 0x300, in step of 0x10. It uses 0x10 ports. + */ +#define SKULL_PORT_FLOOR 0x280 +#define SKULL_PORT_CEIL 0x300 +#define SKULL_PORT_RANGE 0x010 + +/* + * the following function performs autodetection, unless a specific + * value was assigned by insmod to "skull_port_base" + */ + +static int skull_port_base=0; /* 0 forces autodetection */ +module_param(skull_port_base, int, 0); + +static int skull_find_hw(void) /* returns the # of devices */ +{ + /* base is either the load-time value or the first trial */ + int base = skull_port_base ? skull_port_base + : SKULL_PORT_FLOOR; + int result = 0; + + /* loop one time if value assigned, try them all if autodetecting */ + do { + if (skull_detect(base, SKULL_PORT_RANGE) == 0) { + skull_init_board(base); + result++; + } + base += SKULL_PORT_RANGE; /* prepare for next trial */ + } + while (skull_port_base == 0 && base < SKULL_PORT_CEIL); + + return result; +} + + +int skull_init(void) +{ + /* + * Print the isa region map, in blocks of 2K bytes. + * This is not the best code, as it prints too many lines, + * but it deserves to remain short to be included in the book. + * Note also that read() should be used instead of pointers. + */ + unsigned char oldval, newval; /* values read from memory */ + unsigned long flags; /* used to hold system flags */ + unsigned long add, i; + void *base; + + /* Use ioremap to get a handle on our region */ + base = ioremap(ISA_REGION_BEGIN, ISA_REGION_END - ISA_REGION_BEGIN); + base -= ISA_REGION_BEGIN; /* Do the offset once */ + + /* probe all the memory hole in 2KB steps */ + for (add = ISA_REGION_BEGIN; add < ISA_REGION_END; add += STEP) { + /* + * Check for an already allocated region. + */ + if (check_mem_region (add, 2048)) { + printk(KERN_INFO "%lx: Allocated\n", add); + continue; + } + /* + * Read and write the beginning of the region and see what happens. + */ + save_flags(flags); + cli(); + oldval = readb (base + add); /* Read a byte */ + writeb (oldval^0xff, base + add); + mb(); + newval = readb (base + add); + writeb (oldval, base + add); + restore_flags(flags); + + if ((oldval^newval) == 0xff) { /* we re-read our change: it's ram */ + printk(KERN_INFO "%lx: RAM\n", add); + continue; + } + if ((oldval^newval) != 0) { /* random bits changed: it's empty */ + printk(KERN_INFO "%lx: empty\n", add); + continue; + } + + /* + * Expansion rom (executed at boot time by the bios) + * has a signature where the first byt is 0x55, the second 0xaa, + * and the third byte indicates the size of such rom + */ + if ( (oldval == 0x55) && (readb (base + add + 1) == 0xaa)) { + int size = 512 * readb (base + add + 2); + printk(KERN_INFO "%lx: Expansion ROM, %i bytes\n", + add, size); + add += (size & ~2048) - 2048; /* skip it */ + continue; + } + + /* + * If the tests above failed, we still don't know if it is ROM or + * empty. Since empty memory can appear as 0x00, 0xff, or the low + * address byte, we must probe multiple bytes: if at least one of + * them is different from these three values, then this is rom + * (though not boot rom). + */ + printk(KERN_INFO "%lx: ", add); + for (i=0; i<5; i++) { + unsigned long radd = add + 57*(i+1); /* a "random" value */ + unsigned char val = readb (base + radd); + if (val && val != 0xFF && val != ((unsigned long) radd&0xFF)) + break; + } + printk("%s\n", i==5 ? "empty" : "ROM"); + } + + /* + * Find you hardware + */ + skull_find_hw(); + + /* + * Always fail to load (or suceed). + */ + return 0; +} + +module_init(skull_init); -- cgit v1.2.1-18-gbd029