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.
|