Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 <linux/config.h>
 24 #include <linux/module.h>
 25 #include <linux/init.h>
 26 #include <linux/moduleparam.h>
 27 
 28 #include <linux/kernel.h> /* printk */
 29 #include <linux/ioport.h>
 30 #include <linux/errno.h>
 31 #include <asm/system.h> /* cli(), *_flags */
 32 #include <linux/mm.h> /* vremap (2.0) */
 33 #include <asm/io.h> /* 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 
  This page was automatically generated by the LXR engine.