aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/pnpbios
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/pnp/pnpbios
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/pnp/pnpbios')
-rw-r--r--drivers/pnp/pnpbios/Kconfig42
-rw-r--r--drivers/pnp/pnpbios/Makefile7
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c544
-rw-r--r--drivers/pnp/pnpbios/core.c644
-rw-r--r--drivers/pnp/pnpbios/pnpbios.h47
-rw-r--r--drivers/pnp/pnpbios/proc.c292
-rw-r--r--drivers/pnp/pnpbios/rsparser.c795
7 files changed, 2371 insertions, 0 deletions
diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig
new file mode 100644
index 000000000000..fab848cae89d
--- /dev/null
+++ b/drivers/pnp/pnpbios/Kconfig
@@ -0,0 +1,42 @@
1#
2# Plug and Play BIOS configuration
3#
4config PNPBIOS
5 bool "Plug and Play BIOS support (EXPERIMENTAL)"
6 depends on PNP && ISA && X86 && EXPERIMENTAL
7 default n
8 ---help---
9 Linux uses the PNPBIOS as defined in "Plug and Play BIOS
10 Specification Version 1.0A May 5, 1994" to autodetect built-in
11 mainboard resources (e.g. parallel port resources).
12
13 Some features (e.g. event notification, docking station information,
14 ISAPNP services) are not currently implemented.
15
16 If you would like the kernel to detect and allocate resources to
17 your mainboard devices (on some systems they are disabled by the
18 BIOS) say Y here. Also the PNPBIOS can help prevent resource
19 conflicts between mainboard devices and other bus devices.
20
21 Note: ACPI is expected to supersede PNPBIOS some day, currently it
22 co-exists nicely. If you have a non-ISA system that supports ACPI,
23 you probably don't need PNPBIOS support.
24
25config PNPBIOS_PROC_FS
26 bool "Plug and Play BIOS /proc interface"
27 depends on PNPBIOS && PROC_FS
28 ---help---
29 If you say Y here and to "/proc file system support", you will be
30 able to directly access the PNPBIOS. This includes resource
31 allocation, ESCD, and other PNPBIOS services. Using this
32 interface is potentially dangerous because the PNPBIOS driver will
33 not be notified of any resource changes made by writing directly.
34 Also some buggy systems will fault when accessing certain features
35 in the PNPBIOS /proc interface (e.g. "boot" configs).
36
37 See the latest pcmcia-cs (stand-alone package) for a nice set of
38 PNPBIOS /proc interface tools (lspnp and setpnp).
39
40 Unless you are debugging or have other specific reasons, it is
41 recommended that you say N here.
42
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
new file mode 100644
index 000000000000..3cd3ed760605
--- /dev/null
+++ b/drivers/pnp/pnpbios/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the kernel PNPBIOS driver.
3#
4
5pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
6
7obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
new file mode 100644
index 000000000000..6b7583f497d0
--- /dev/null
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -0,0 +1,544 @@
1/*
2 * bioscalls.c - the lowlevel layer of the PnPBIOS driver
3 *
4 */
5
6#include <linux/types.h>
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/linkage.h>
10#include <linux/kernel.h>
11#include <linux/pnpbios.h>
12#include <linux/device.h>
13#include <linux/pnp.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/slab.h>
17#include <linux/kmod.h>
18#include <linux/completion.h>
19#include <linux/spinlock.h>
20
21#include <asm/page.h>
22#include <asm/desc.h>
23#include <asm/system.h>
24#include <asm/byteorder.h>
25
26#include "pnpbios.h"
27
28static struct {
29 u16 offset;
30 u16 segment;
31} pnp_bios_callpoint;
32
33
34/* The PnP BIOS entries in the GDT */
35#define PNP_GDT (GDT_ENTRY_PNPBIOS_BASE * 8)
36
37#define PNP_CS32 (PNP_GDT+0x00) /* segment for calling fn */
38#define PNP_CS16 (PNP_GDT+0x08) /* code segment for BIOS */
39#define PNP_DS (PNP_GDT+0x10) /* data segment for BIOS */
40#define PNP_TS1 (PNP_GDT+0x18) /* transfer data segment */
41#define PNP_TS2 (PNP_GDT+0x20) /* another data segment */
42
43/*
44 * These are some opcodes for a "static asmlinkage"
45 * As this code is *not* executed inside the linux kernel segment, but in a
46 * alias at offset 0, we need a far return that can not be compiled by
47 * default (please, prove me wrong! this is *really* ugly!)
48 * This is the only way to get the bios to return into the kernel code,
49 * because the bios code runs in 16 bit protected mode and therefore can only
50 * return to the caller if the call is within the first 64kB, and the linux
51 * kernel begins at offset 3GB...
52 */
53
54asmlinkage void pnp_bios_callfunc(void);
55
56__asm__(
57 ".text \n"
58 __ALIGN_STR "\n"
59 "pnp_bios_callfunc:\n"
60 " pushl %edx \n"
61 " pushl %ecx \n"
62 " pushl %ebx \n"
63 " pushl %eax \n"
64 " lcallw *pnp_bios_callpoint\n"
65 " addl $16, %esp \n"
66 " lret \n"
67 ".previous \n"
68);
69
70#define Q_SET_SEL(cpu, selname, address, size) \
71do { \
72set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \
73set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \
74} while(0)
75
76#define Q2_SET_SEL(cpu, selname, address, size) \
77do { \
78set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \
79set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \
80} while(0)
81
82static struct desc_struct bad_bios_desc = { 0, 0x00409200 };
83
84/*
85 * At some point we want to use this stack frame pointer to unwind
86 * after PnP BIOS oopses.
87 */
88
89u32 pnp_bios_fault_esp;
90u32 pnp_bios_fault_eip;
91u32 pnp_bios_is_utter_crap = 0;
92
93static spinlock_t pnp_bios_lock;
94
95
96/*
97 * Support Functions
98 */
99
100static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
101 u16 arg4, u16 arg5, u16 arg6, u16 arg7,
102 void *ts1_base, u32 ts1_size,
103 void *ts2_base, u32 ts2_size)
104{
105 unsigned long flags;
106 u16 status;
107 struct desc_struct save_desc_40;
108 int cpu;
109
110 /*
111 * PnP BIOSes are generally not terribly re-entrant.
112 * Also, don't rely on them to save everything correctly.
113 */
114 if(pnp_bios_is_utter_crap)
115 return PNP_FUNCTION_NOT_SUPPORTED;
116
117 cpu = get_cpu();
118 save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8];
119 per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc;
120
121 /* On some boxes IRQ's during PnP BIOS calls are deadly. */
122 spin_lock_irqsave(&pnp_bios_lock, flags);
123
124 /* The lock prevents us bouncing CPU here */
125 if (ts1_size)
126 Q2_SET_SEL(smp_processor_id(), PNP_TS1, ts1_base, ts1_size);
127 if (ts2_size)
128 Q2_SET_SEL(smp_processor_id(), PNP_TS2, ts2_base, ts2_size);
129
130 __asm__ __volatile__(
131 "pushl %%ebp\n\t"
132 "pushl %%edi\n\t"
133 "pushl %%esi\n\t"
134 "pushl %%ds\n\t"
135 "pushl %%es\n\t"
136 "pushl %%fs\n\t"
137 "pushl %%gs\n\t"
138 "pushfl\n\t"
139 "movl %%esp, pnp_bios_fault_esp\n\t"
140 "movl $1f, pnp_bios_fault_eip\n\t"
141 "lcall %5,%6\n\t"
142 "1:popfl\n\t"
143 "popl %%gs\n\t"
144 "popl %%fs\n\t"
145 "popl %%es\n\t"
146 "popl %%ds\n\t"
147 "popl %%esi\n\t"
148 "popl %%edi\n\t"
149 "popl %%ebp\n\t"
150 : "=a" (status)
151 : "0" ((func) | (((u32)arg1) << 16)),
152 "b" ((arg2) | (((u32)arg3) << 16)),
153 "c" ((arg4) | (((u32)arg5) << 16)),
154 "d" ((arg6) | (((u32)arg7) << 16)),
155 "i" (PNP_CS32),
156 "i" (0)
157 : "memory"
158 );
159 spin_unlock_irqrestore(&pnp_bios_lock, flags);
160
161 per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40;
162 put_cpu();
163
164 /* If we get here and this is set then the PnP BIOS faulted on us. */
165 if(pnp_bios_is_utter_crap)
166 {
167 printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
168 printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
169 printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
170 }
171
172 return status;
173}
174
175void pnpbios_print_status(const char * module, u16 status)
176{
177 switch(status) {
178 case PNP_SUCCESS:
179 printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
180 break;
181 case PNP_NOT_SET_STATICALLY:
182 printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
183 break;
184 case PNP_UNKNOWN_FUNCTION:
185 printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
186 break;
187 case PNP_FUNCTION_NOT_SUPPORTED:
188 printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
189 break;
190 case PNP_INVALID_HANDLE:
191 printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
192 break;
193 case PNP_BAD_PARAMETER:
194 printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
195 break;
196 case PNP_SET_FAILED:
197 printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
198 break;
199 case PNP_EVENTS_NOT_PENDING:
200 printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
201 break;
202 case PNP_SYSTEM_NOT_DOCKED:
203 printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
204 break;
205 case PNP_NO_ISA_PNP_CARDS:
206 printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
207 break;
208 case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
209 printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
210 break;
211 case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
212 printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
213 break;
214 case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
215 printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
216 break;
217 case PNP_BUFFER_TOO_SMALL:
218 printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
219 break;
220 case PNP_USE_ESCD_SUPPORT:
221 printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
222 break;
223 case PNP_MESSAGE_NOT_SUPPORTED:
224 printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
225 break;
226 case PNP_HARDWARE_ERROR:
227 printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
228 break;
229 default:
230 printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
231 break;
232 }
233}
234
235
236/*
237 * PnP BIOS Low Level Calls
238 */
239
240#define PNP_GET_NUM_SYS_DEV_NODES 0x00
241#define PNP_GET_SYS_DEV_NODE 0x01
242#define PNP_SET_SYS_DEV_NODE 0x02
243#define PNP_GET_EVENT 0x03
244#define PNP_SEND_MESSAGE 0x04
245#define PNP_GET_DOCKING_STATION_INFORMATION 0x05
246#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
247#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
248#define PNP_GET_APM_ID_TABLE 0x0b
249#define PNP_GET_PNP_ISA_CONFIG_STRUC 0x40
250#define PNP_GET_ESCD_INFO 0x41
251#define PNP_READ_ESCD 0x42
252#define PNP_WRITE_ESCD 0x43
253
254/*
255 * Call PnP BIOS with function 0x00, "get number of system device nodes"
256 */
257static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
258{
259 u16 status;
260 if (!pnp_bios_present())
261 return PNP_FUNCTION_NOT_SUPPORTED;
262 status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0,
263 data, sizeof(struct pnp_dev_node_info), NULL, 0);
264 data->no_nodes &= 0xff;
265 return status;
266}
267
268int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
269{
270 int status = __pnp_bios_dev_node_info( data );
271 if ( status )
272 pnpbios_print_status( "dev_node_info", status );
273 return status;
274}
275
276/*
277 * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible
278 * death if they are asked to access the "current" configuration.
279 * Therefore, if it's a matter of indifference, it's better to call
280 * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0.
281 */
282
283/*
284 * Call PnP BIOS with function 0x01, "get system device node"
285 * Input: *nodenum = desired node,
286 * boot = whether to get nonvolatile boot (!=0)
287 * or volatile current (0) config
288 * Output: *nodenum=next node or 0xff if no more nodes
289 */
290static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
291{
292 u16 status;
293 if (!pnp_bios_present())
294 return PNP_FUNCTION_NOT_SUPPORTED;
295 if ( !boot && pnpbios_dont_use_current_config )
296 return PNP_FUNCTION_NOT_SUPPORTED;
297 status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
298 nodenum, sizeof(char), data, 65536);
299 return status;
300}
301
302int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
303{
304 int status;
305 status = __pnp_bios_get_dev_node( nodenum, boot, data );
306 if ( status )
307 pnpbios_print_status( "get_dev_node", status );
308 return status;
309}
310
311
312/*
313 * Call PnP BIOS with function 0x02, "set system device node"
314 * Input: *nodenum = desired node,
315 * boot = whether to set nonvolatile boot (!=0)
316 * or volatile current (0) config
317 */
318static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
319{
320 u16 status;
321 if (!pnp_bios_present())
322 return PNP_FUNCTION_NOT_SUPPORTED;
323 if ( !boot && pnpbios_dont_use_current_config )
324 return PNP_FUNCTION_NOT_SUPPORTED;
325 status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
326 data, 65536, NULL, 0);
327 return status;
328}
329
330int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
331{
332 int status;
333 status = __pnp_bios_set_dev_node( nodenum, boot, data );
334 if ( status ) {
335 pnpbios_print_status( "set_dev_node", status );
336 return status;
337 }
338 if ( !boot ) { /* Update devlist */
339 status = pnp_bios_get_dev_node( &nodenum, boot, data );
340 if ( status )
341 return status;
342 }
343 return status;
344}
345
346#if needed
347/*
348 * Call PnP BIOS with function 0x03, "get event"
349 */
350static int pnp_bios_get_event(u16 *event)
351{
352 u16 status;
353 if (!pnp_bios_present())
354 return PNP_FUNCTION_NOT_SUPPORTED;
355 status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0,
356 event, sizeof(u16), NULL, 0);
357 return status;
358}
359#endif
360
361#if needed
362/*
363 * Call PnP BIOS with function 0x04, "send message"
364 */
365static int pnp_bios_send_message(u16 message)
366{
367 u16 status;
368 if (!pnp_bios_present())
369 return PNP_FUNCTION_NOT_SUPPORTED;
370 status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0);
371 return status;
372}
373#endif
374
375/*
376 * Call PnP BIOS with function 0x05, "get docking station information"
377 */
378int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
379{
380 u16 status;
381 if (!pnp_bios_present())
382 return PNP_FUNCTION_NOT_SUPPORTED;
383 status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
384 data, sizeof(struct pnp_docking_station_info), NULL, 0);
385 return status;
386}
387
388#if needed
389/*
390 * Call PnP BIOS with function 0x09, "set statically allocated resource
391 * information"
392 */
393static int pnp_bios_set_stat_res(char *info)
394{
395 u16 status;
396 if (!pnp_bios_present())
397 return PNP_FUNCTION_NOT_SUPPORTED;
398 status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
399 info, *((u16 *) info), 0, 0);
400 return status;
401}
402#endif
403
404/*
405 * Call PnP BIOS with function 0x0a, "get statically allocated resource
406 * information"
407 */
408static int __pnp_bios_get_stat_res(char *info)
409{
410 u16 status;
411 if (!pnp_bios_present())
412 return PNP_FUNCTION_NOT_SUPPORTED;
413 status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
414 info, 65536, NULL, 0);
415 return status;
416}
417
418int pnp_bios_get_stat_res(char *info)
419{
420 int status;
421 status = __pnp_bios_get_stat_res( info );
422 if ( status )
423 pnpbios_print_status( "get_stat_res", status );
424 return status;
425}
426
427#if needed
428/*
429 * Call PnP BIOS with function 0x0b, "get APM id table"
430 */
431static int pnp_bios_apm_id_table(char *table, u16 *size)
432{
433 u16 status;
434 if (!pnp_bios_present())
435 return PNP_FUNCTION_NOT_SUPPORTED;
436 status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0,
437 table, *size, size, sizeof(u16));
438 return status;
439}
440#endif
441
442/*
443 * Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
444 */
445static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
446{
447 u16 status;
448 if (!pnp_bios_present())
449 return PNP_FUNCTION_NOT_SUPPORTED;
450 status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
451 data, sizeof(struct pnp_isa_config_struc), NULL, 0);
452 return status;
453}
454
455int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
456{
457 int status;
458 status = __pnp_bios_isapnp_config( data );
459 if ( status )
460 pnpbios_print_status( "isapnp_config", status );
461 return status;
462}
463
464/*
465 * Call PnP BIOS with function 0x41, "get ESCD info"
466 */
467static int __pnp_bios_escd_info(struct escd_info_struc *data)
468{
469 u16 status;
470 if (!pnp_bios_present())
471 return ESCD_FUNCTION_NOT_SUPPORTED;
472 status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS,
473 data, sizeof(struct escd_info_struc), NULL, 0);
474 return status;
475}
476
477int pnp_bios_escd_info(struct escd_info_struc *data)
478{
479 int status;
480 status = __pnp_bios_escd_info( data );
481 if ( status )
482 pnpbios_print_status( "escd_info", status );
483 return status;
484}
485
486/*
487 * Call PnP BIOS function 0x42, "read ESCD"
488 * nvram_base is determined by calling escd_info
489 */
490static int __pnp_bios_read_escd(char *data, u32 nvram_base)
491{
492 u16 status;
493 if (!pnp_bios_present())
494 return ESCD_FUNCTION_NOT_SUPPORTED;
495 status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
496 data, 65536, __va(nvram_base), 65536);
497 return status;
498}
499
500int pnp_bios_read_escd(char *data, u32 nvram_base)
501{
502 int status;
503 status = __pnp_bios_read_escd( data, nvram_base );
504 if ( status )
505 pnpbios_print_status( "read_escd", status );
506 return status;
507}
508
509#if needed
510/*
511 * Call PnP BIOS function 0x43, "write ESCD"
512 */
513static int pnp_bios_write_escd(char *data, u32 nvram_base)
514{
515 u16 status;
516 if (!pnp_bios_present())
517 return ESCD_FUNCTION_NOT_SUPPORTED;
518 status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
519 data, 65536, __va(nvram_base), 65536);
520 return status;
521}
522#endif
523
524
525/*
526 * Initialization
527 */
528
529void pnpbios_calls_init(union pnp_bios_install_struct *header)
530{
531 int i;
532 spin_lock_init(&pnp_bios_lock);
533 pnp_bios_callpoint.offset = header->fields.pm16offset;
534 pnp_bios_callpoint.segment = PNP_CS16;
535
536 set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
537 _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
538 for(i=0; i < NR_CPUS; i++)
539 {
540 Q2_SET_SEL(i, PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
541 Q_SET_SEL(i, PNP_CS16, header->fields.pm16cseg, 64 * 1024);
542 Q_SET_SEL(i, PNP_DS, header->fields.pm16dseg, 64 * 1024);
543 }
544}
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
new file mode 100644
index 000000000000..0f6330b3af12
--- /dev/null
+++ b/drivers/pnp/pnpbios/core.c
@@ -0,0 +1,644 @@
1/*
2 * pnpbios -- PnP BIOS driver
3 *
4 * This driver provides access to Plug-'n'-Play services provided by
5 * the PnP BIOS firmware, described in the following documents:
6 * Plug and Play BIOS Specification, Version 1.0A, 5 May 1994
7 * Plug and Play BIOS Clarification Paper, 6 October 1994
8 * Compaq Computer Corporation, Phoenix Technologies Ltd., Intel Corp.
9 *
10 * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
11 * Modifications (C) 1998 Tom Lees <tom@lpsg.demon.co.uk>
12 * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
13 * Further modifications (C) 2001, 2002 by:
14 * Alan Cox <alan@redhat.com>
15 * Thomas Hood
16 * Brian Gerst <bgerst@didntduck.org>
17 *
18 * Ported to the PnP Layer and several additional improvements (C) 2002
19 * by Adam Belay <ambx1@neo.rr.com>
20 *
21 * This program is free software; you can redistribute it and/or modify it
22 * under the terms of the GNU General Public License as published by the
23 * Free Software Foundation; either version 2, or (at your option) any
24 * later version.
25 *
26 * This program is distributed in the hope that it will be useful, but
27 * WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 */
35
36/* Change Log
37 *
38 * Adam Belay - <ambx1@neo.rr.com> - March 16, 2003
39 * rev 1.01 Only call pnp_bios_dev_node_info once
40 * Added pnpbios_print_status
41 * Added several new error messages and info messages
42 * Added pnpbios_interface_attach_device
43 * integrated core and proc init system
44 * Introduced PNPMODE flags
45 * Removed some useless includes
46 */
47
48#include <linux/types.h>
49#include <linux/module.h>
50#include <linux/init.h>
51#include <linux/linkage.h>
52#include <linux/kernel.h>
53#include <linux/pnpbios.h>
54#include <linux/device.h>
55#include <linux/pnp.h>
56#include <linux/mm.h>
57#include <linux/smp.h>
58#include <linux/slab.h>
59#include <linux/kobject_uevent.h>
60#include <linux/completion.h>
61#include <linux/spinlock.h>
62#include <linux/dmi.h>
63#include <linux/delay.h>
64#include <linux/acpi.h>
65
66#include <asm/page.h>
67#include <asm/desc.h>
68#include <asm/system.h>
69#include <asm/byteorder.h>
70
71#include "pnpbios.h"
72
73
74/*
75 *
76 * PnP BIOS INTERFACE
77 *
78 */
79
80static union pnp_bios_install_struct * pnp_bios_install = NULL;
81
82int pnp_bios_present(void)
83{
84 return (pnp_bios_install != NULL);
85}
86
87struct pnp_dev_node_info node_info;
88
89void *pnpbios_kmalloc(size_t size, int f)
90{
91 void *p = kmalloc( size, f );
92 if ( p == NULL )
93 printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
94 else
95 memset(p, 0, size);
96 return p;
97}
98
99/*
100 *
101 * DOCKING FUNCTIONS
102 *
103 */
104
105#ifdef CONFIG_HOTPLUG
106
107static int unloading = 0;
108static struct completion unload_sem;
109
110/*
111 * (Much of this belongs in a shared routine somewhere)
112 */
113
114static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
115{
116 char *argv [3], **envp, *buf, *scratch;
117 int i = 0, value;
118
119 if (!hotplug_path [0])
120 return -ENOENT;
121 if (!current->fs->root) {
122 return -EAGAIN;
123 }
124 if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
125 return -ENOMEM;
126 }
127 if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
128 kfree (envp);
129 return -ENOMEM;
130 }
131
132 /* only one standardized param to hotplug command: type */
133 argv [0] = hotplug_path;
134 argv [1] = "dock";
135 argv [2] = NULL;
136
137 /* minimal command environment */
138 envp [i++] = "HOME=/";
139 envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
140
141#ifdef DEBUG
142 /* hint that policy agent should enter no-stdout debug mode */
143 envp [i++] = "DEBUG=kernel";
144#endif
145 /* extensible set of named bus-specific parameters,
146 * supporting multiple driver selection algorithms.
147 */
148 scratch = buf;
149
150 /* action: add, remove */
151 envp [i++] = scratch;
152 scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
153
154 /* Report the ident for the dock */
155 envp [i++] = scratch;
156 scratch += sprintf (scratch, "DOCK=%x/%x/%x",
157 info->location_id, info->serial, info->capabilities);
158 envp[i] = NULL;
159
160 value = call_usermodehelper (argv [0], argv, envp, 0);
161 kfree (buf);
162 kfree (envp);
163 return 0;
164}
165
166/*
167 * Poll the PnP docking at regular intervals
168 */
169static int pnp_dock_thread(void * unused)
170{
171 static struct pnp_docking_station_info now;
172 int docked = -1, d = 0;
173 daemonize("kpnpbiosd");
174 allow_signal(SIGKILL);
175 while(!unloading && !signal_pending(current))
176 {
177 int status;
178
179 /*
180 * Poll every 2 seconds
181 */
182 msleep_interruptible(2000);
183
184 if(signal_pending(current)) {
185 if (try_to_freeze(PF_FREEZE))
186 continue;
187 break;
188 }
189
190 status = pnp_bios_dock_station_info(&now);
191
192 switch(status)
193 {
194 /*
195 * No dock to manage
196 */
197 case PNP_FUNCTION_NOT_SUPPORTED:
198 complete_and_exit(&unload_sem, 0);
199 case PNP_SYSTEM_NOT_DOCKED:
200 d = 0;
201 break;
202 case PNP_SUCCESS:
203 d = 1;
204 break;
205 default:
206 pnpbios_print_status( "pnp_dock_thread", status );
207 continue;
208 }
209 if(d != docked)
210 {
211 if(pnp_dock_event(d, &now)==0)
212 {
213 docked = d;
214#if 0
215 printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
216#endif
217 }
218 }
219 }
220 complete_and_exit(&unload_sem, 0);
221}
222
223#endif /* CONFIG_HOTPLUG */
224
225static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
226{
227 u8 nodenum = dev->number;
228 struct pnp_bios_node * node;
229
230 /* just in case */
231 if(!pnpbios_is_dynamic(dev))
232 return -EPERM;
233
234 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
235 if (!node)
236 return -1;
237 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
238 kfree(node);
239 return -ENODEV;
240 }
241 pnpbios_read_resources_from_node(res, node);
242 dev->active = pnp_is_active(dev);
243 kfree(node);
244 return 0;
245}
246
247static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
248{
249 u8 nodenum = dev->number;
250 struct pnp_bios_node * node;
251 int ret;
252
253 /* just in case */
254 if (!pnpbios_is_dynamic(dev))
255 return -EPERM;
256
257 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
258 if (!node)
259 return -1;
260 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
261 kfree(node);
262 return -ENODEV;
263 }
264 if(pnpbios_write_resources_to_node(res, node)<0) {
265 kfree(node);
266 return -1;
267 }
268 ret = pnp_bios_set_dev_node(node->handle, (char)PNPMODE_DYNAMIC, node);
269 kfree(node);
270 if (ret > 0)
271 ret = -1;
272 return ret;
273}
274
275static void pnpbios_zero_data_stream(struct pnp_bios_node * node)
276{
277 unsigned char * p = (char *)node->data;
278 unsigned char * end = (char *)(node->data + node->size);
279 unsigned int len;
280 int i;
281 while ((char *)p < (char *)end) {
282 if(p[0] & 0x80) { /* large tag */
283 len = (p[2] << 8) | p[1];
284 p += 3;
285 } else {
286 if (((p[0]>>3) & 0x0f) == 0x0f)
287 return;
288 len = p[0] & 0x07;
289 p += 1;
290 }
291 for (i = 0; i < len; i++)
292 p[i] = 0;
293 p += len;
294 }
295 printk(KERN_ERR "PnPBIOS: Resource structure did not contain an end tag.\n");
296}
297
298static int pnpbios_disable_resources(struct pnp_dev *dev)
299{
300 struct pnp_bios_node * node;
301 u8 nodenum = dev->number;
302 int ret;
303
304 /* just in case */
305 if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
306 return -EPERM;
307
308 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
309 if (!node)
310 return -ENOMEM;
311
312 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
313 kfree(node);
314 return -ENODEV;
315 }
316 pnpbios_zero_data_stream(node);
317
318 ret = pnp_bios_set_dev_node(dev->number, (char)PNPMODE_DYNAMIC, node);
319 kfree(node);
320 if (ret > 0)
321 ret = -1;
322 return ret;
323}
324
325/* PnP Layer support */
326
327struct pnp_protocol pnpbios_protocol = {
328 .name = "Plug and Play BIOS",
329 .get = pnpbios_get_resources,
330 .set = pnpbios_set_resources,
331 .disable = pnpbios_disable_resources,
332};
333
334static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
335{
336 struct list_head * pos;
337 struct pnp_dev * pnp_dev;
338 struct pnp_id *dev_id;
339 char id[8];
340
341 /* check if the device is already added */
342 dev->number = node->handle;
343 list_for_each (pos, &pnpbios_protocol.devices){
344 pnp_dev = list_entry(pos, struct pnp_dev, protocol_list);
345 if (dev->number == pnp_dev->number)
346 return -1;
347 }
348
349 /* set the initial values for the PnP device */
350 dev_id = pnpbios_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
351 if (!dev_id)
352 return -1;
353 pnpid32_to_pnpid(node->eisa_id,id);
354 memcpy(dev_id->id,id,7);
355 pnp_add_id(dev_id, dev);
356 pnpbios_parse_data_stream(dev, node);
357 dev->active = pnp_is_active(dev);
358 dev->flags = node->flags;
359 if (!(dev->flags & PNPBIOS_NO_CONFIG))
360 dev->capabilities |= PNP_CONFIGURABLE;
361 if (!(dev->flags & PNPBIOS_NO_DISABLE))
362 dev->capabilities |= PNP_DISABLE;
363 dev->capabilities |= PNP_READ;
364 if (pnpbios_is_dynamic(dev))
365 dev->capabilities |= PNP_WRITE;
366 if (dev->flags & PNPBIOS_REMOVABLE)
367 dev->capabilities |= PNP_REMOVABLE;
368 dev->protocol = &pnpbios_protocol;
369
370 /* clear out the damaged flags */
371 if (!dev->active)
372 pnp_init_resource_table(&dev->res);
373
374 pnp_add_device(dev);
375 pnpbios_interface_attach_device(node);
376
377 return 0;
378}
379
380static void __init build_devlist(void)
381{
382 u8 nodenum;
383 unsigned int nodes_got = 0;
384 unsigned int devs = 0;
385 struct pnp_bios_node *node;
386 struct pnp_dev *dev;
387
388 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
389 if (!node)
390 return;
391
392 for(nodenum=0; nodenum<0xff; ) {
393 u8 thisnodenum = nodenum;
394 /* eventually we will want to use PNPMODE_STATIC here but for now
395 * dynamic will help us catch buggy bioses to add to the blacklist.
396 */
397 if (!pnpbios_dont_use_current_config) {
398 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node))
399 break;
400 } else {
401 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node))
402 break;
403 }
404 nodes_got++;
405 dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
406 if (!dev)
407 break;
408 if(insert_device(dev,node)<0)
409 kfree(dev);
410 else
411 devs++;
412 if (nodenum <= thisnodenum) {
413 printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
414 break;
415 }
416 }
417 kfree(node);
418
419 printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
420 nodes_got, nodes_got != 1 ? "s" : "", devs);
421}
422
423/*
424 *
425 * INIT AND EXIT
426 *
427 */
428
429static int pnpbios_disabled; /* = 0 */
430int pnpbios_dont_use_current_config; /* = 0 */
431
432#ifndef MODULE
433static int __init pnpbios_setup(char *str)
434{
435 int invert;
436
437 while ((str != NULL) && (*str != '\0')) {
438 if (strncmp(str, "off", 3) == 0)
439 pnpbios_disabled=1;
440 if (strncmp(str, "on", 2) == 0)
441 pnpbios_disabled=0;
442 invert = (strncmp(str, "no-", 3) == 0);
443 if (invert)
444 str += 3;
445 if (strncmp(str, "curr", 4) == 0)
446 pnpbios_dont_use_current_config = invert;
447 str = strchr(str, ',');
448 if (str != NULL)
449 str += strspn(str, ", \t");
450 }
451
452 return 1;
453}
454
455__setup("pnpbios=", pnpbios_setup);
456#endif
457
458/* PnP BIOS signature: "$PnP" */
459#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
460
461static int __init pnpbios_probe_system(void)
462{
463 union pnp_bios_install_struct *check;
464 u8 sum;
465 int length, i;
466
467 printk(KERN_INFO "PnPBIOS: Scanning system for PnP BIOS support...\n");
468
469 /*
470 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
471 * structure and, if one is found, sets up the selectors and
472 * entry points
473 */
474 for (check = (union pnp_bios_install_struct *) __va(0xf0000);
475 check < (union pnp_bios_install_struct *) __va(0xffff0);
476 check = (void *)check + 16) {
477 if (check->fields.signature != PNP_SIGNATURE)
478 continue;
479 printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
480 length = check->fields.length;
481 if (!length) {
482 printk(KERN_ERR "PnPBIOS: installation structure is invalid, skipping\n");
483 continue;
484 }
485 for (sum = 0, i = 0; i < length; i++)
486 sum += check->chars[i];
487 if (sum) {
488 printk(KERN_ERR "PnPBIOS: installation structure is corrupted, skipping\n");
489 continue;
490 }
491 if (check->fields.version < 0x10) {
492 printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
493 check->fields.version >> 4,
494 check->fields.version & 15);
495 continue;
496 }
497 printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
498 check->fields.version >> 4, check->fields.version & 15,
499 check->fields.pm16cseg, check->fields.pm16offset,
500 check->fields.pm16dseg);
501 pnp_bios_install = check;
502 return 1;
503 }
504
505 printk(KERN_INFO "PnPBIOS: PnP BIOS support was not detected.\n");
506 return 0;
507}
508
509static int __init exploding_pnp_bios(struct dmi_system_id *d)
510{
511 printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident);
512 return 0;
513}
514
515static struct dmi_system_id pnpbios_dmi_table[] = {
516 { /* PnPBIOS GPF on boot */
517 .callback = exploding_pnp_bios,
518 .ident = "Higraded P14H",
519 .matches = {
520 DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
521 DMI_MATCH(DMI_BIOS_VERSION, "07.00T"),
522 DMI_MATCH(DMI_SYS_VENDOR, "Higraded"),
523 DMI_MATCH(DMI_PRODUCT_NAME, "P14H"),
524 },
525 },
526 { /* PnPBIOS GPF on boot */
527 .callback = exploding_pnp_bios,
528 .ident = "ASUS P4P800",
529 .matches = {
530 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
531 DMI_MATCH(DMI_BOARD_NAME, "P4P800"),
532 },
533 },
534 { }
535};
536
537static int __init pnpbios_init(void)
538{
539 int ret;
540
541 if (pnpbios_disabled || dmi_check_system(pnpbios_dmi_table)) {
542 printk(KERN_INFO "PnPBIOS: Disabled\n");
543 return -ENODEV;
544 }
545
546#ifdef CONFIG_PNPACPI
547 if (!acpi_disabled && !pnpacpi_disabled) {
548 pnpbios_disabled = 1;
549 printk(KERN_INFO "PnPBIOS: Disabled by ACPI PNP\n");
550 return -ENODEV;
551 }
552#endif /* CONFIG_ACPI */
553
554 /* scan the system for pnpbios support */
555 if (!pnpbios_probe_system())
556 return -ENODEV;
557
558 /* make preparations for bios calls */
559 pnpbios_calls_init(pnp_bios_install);
560
561 /* read the node info */
562 ret = pnp_bios_dev_node_info(&node_info);
563 if (ret) {
564 printk(KERN_ERR "PnPBIOS: Unable to get node info. Aborting.\n");
565 return ret;
566 }
567
568 /* register with the pnp layer */
569 ret = pnp_register_protocol(&pnpbios_protocol);
570 if (ret) {
571 printk(KERN_ERR "PnPBIOS: Unable to register driver. Aborting.\n");
572 return ret;
573 }
574
575 /* start the proc interface */
576 ret = pnpbios_proc_init();
577 if (ret)
578 printk(KERN_ERR "PnPBIOS: Failed to create proc interface.\n");
579
580 /* scan for pnpbios devices */
581 build_devlist();
582
583 return 0;
584}
585
586subsys_initcall(pnpbios_init);
587
588static int __init pnpbios_thread_init(void)
589{
590 if (pnpbios_disabled)
591 return 0;
592#ifdef CONFIG_HOTPLUG
593 init_completion(&unload_sem);
594 if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0)
595 unloading = 0;
596#endif
597 return 0;
598}
599
600#ifndef MODULE
601
602/* init/main.c calls pnpbios_init early */
603
604/* Start the kernel thread later: */
605module_init(pnpbios_thread_init);
606
607#else
608
609/*
610 * N.B.: Building pnpbios as a module hasn't been fully implemented
611 */
612
613MODULE_LICENSE("GPL");
614
615static int __init pnpbios_init_all(void)
616{
617 int r;
618
619 r = pnpbios_init();
620 if (r)
621 return r;
622 r = pnpbios_thread_init();
623 if (r)
624 return r;
625 return 0;
626}
627
628static void __exit pnpbios_exit(void)
629{
630#ifdef CONFIG_HOTPLUG
631 unloading = 1;
632 wait_for_completion(&unload_sem);
633#endif
634 pnpbios_proc_exit();
635 /* We ought to free resources here */
636 return;
637}
638
639module_init(pnpbios_init_all);
640module_exit(pnpbios_exit);
641
642#endif
643
644EXPORT_SYMBOL(pnpbios_protocol);
diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h
new file mode 100644
index 000000000000..01896e705ed4
--- /dev/null
+++ b/drivers/pnp/pnpbios/pnpbios.h
@@ -0,0 +1,47 @@
1/*
2 * pnpbios.h - contains local definitions
3 */
4
5#pragma pack(1)
6union pnp_bios_install_struct {
7 struct {
8 u32 signature; /* "$PnP" */
9 u8 version; /* in BCD */
10 u8 length; /* length in bytes, currently 21h */
11 u16 control; /* system capabilities */
12 u8 checksum; /* all bytes must add up to 0 */
13
14 u32 eventflag; /* phys. address of the event flag */
15 u16 rmoffset; /* real mode entry point */
16 u16 rmcseg;
17 u16 pm16offset; /* 16 bit protected mode entry */
18 u32 pm16cseg;
19 u32 deviceID; /* EISA encoded system ID or 0 */
20 u16 rmdseg; /* real mode data segment */
21 u32 pm16dseg; /* 16 bit pm data segment base */
22 } fields;
23 char chars[0x21]; /* To calculate the checksum */
24};
25#pragma pack()
26
27extern int pnp_bios_present(void);
28extern int pnpbios_dont_use_current_config;
29extern void *pnpbios_kmalloc(size_t size, int f);
30
31extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node);
32extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
33extern int pnpbios_write_resources_to_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
34extern void pnpid32_to_pnpid(u32 id, char *str);
35
36extern void pnpbios_print_status(const char * module, u16 status);
37extern void pnpbios_calls_init(union pnp_bios_install_struct * header);
38
39#ifdef CONFIG_PNPBIOS_PROC_FS
40extern int pnpbios_interface_attach_device(struct pnp_bios_node * node);
41extern int pnpbios_proc_init (void);
42extern void pnpbios_proc_exit (void);
43#else
44static inline int pnpbios_interface_attach_device(struct pnp_bios_node * node) { return 0; }
45static inline int pnpbios_proc_init (void) { return 0; }
46static inline void pnpbios_proc_exit (void) { ; }
47#endif /* CONFIG_PNPBIOS_PROC_FS */
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
new file mode 100644
index 000000000000..6bb8e1973fd4
--- /dev/null
+++ b/drivers/pnp/pnpbios/proc.c
@@ -0,0 +1,292 @@
1/*
2 * /proc/bus/pnp interface for Plug and Play devices
3 *
4 * Written by David Hinds, dahinds@users.sourceforge.net
5 * Modified by Thomas Hood
6 *
7 * The .../devices and .../<node> and .../boot/<node> files are
8 * utilized by the lspnp and setpnp utilities, supplied with the
9 * pcmcia-cs package.
10 * http://pcmcia-cs.sourceforge.net
11 *
12 * The .../escd file is utilized by the lsescd utility written by
13 * Gunther Mayer.
14 * http://home.t-online.de/home/gunther.mayer/lsescd
15 *
16 * The .../legacy_device_resources file is not used yet.
17 *
18 * The other files are human-readable.
19 */
20
21//#include <pcmcia/config.h>
22//#include <pcmcia/k_compat.h>
23
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/slab.h>
27#include <linux/types.h>
28#include <linux/proc_fs.h>
29#include <linux/pnpbios.h>
30#include <linux/init.h>
31
32#include <asm/uaccess.h>
33
34#include "pnpbios.h"
35
36static struct proc_dir_entry *proc_pnp = NULL;
37static struct proc_dir_entry *proc_pnp_boot = NULL;
38
39static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
40 int count, int *eof, void *data)
41{
42 struct pnp_isa_config_struc pnps;
43
44 if (pnp_bios_isapnp_config(&pnps))
45 return -EIO;
46 return snprintf(buf, count,
47 "structure_revision %d\n"
48 "number_of_CSNs %d\n"
49 "ISA_read_data_port 0x%x\n",
50 pnps.revision,
51 pnps.no_csns,
52 pnps.isa_rd_data_port
53 );
54}
55
56static int proc_read_escdinfo(char *buf, char **start, off_t pos,
57 int count, int *eof, void *data)
58{
59 struct escd_info_struc escd;
60
61 if (pnp_bios_escd_info(&escd))
62 return -EIO;
63 return snprintf(buf, count,
64 "min_ESCD_write_size %d\n"
65 "ESCD_size %d\n"
66 "NVRAM_base 0x%x\n",
67 escd.min_escd_write_size,
68 escd.escd_size,
69 escd.nv_storage_base
70 );
71}
72
73#define MAX_SANE_ESCD_SIZE (32*1024)
74static int proc_read_escd(char *buf, char **start, off_t pos,
75 int count, int *eof, void *data)
76{
77 struct escd_info_struc escd;
78 char *tmpbuf;
79 int escd_size, escd_left_to_read, n;
80
81 if (pnp_bios_escd_info(&escd))
82 return -EIO;
83
84 /* sanity check */
85 if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
86 printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
87 return -EFBIG;
88 }
89
90 tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
91 if (!tmpbuf) return -ENOMEM;
92
93 if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
94 kfree(tmpbuf);
95 return -EIO;
96 }
97
98 escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256;
99
100 /* sanity check */
101 if (escd_size > MAX_SANE_ESCD_SIZE) {
102 printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
103 return -EFBIG;
104 }
105
106 escd_left_to_read = escd_size - pos;
107 if (escd_left_to_read < 0) escd_left_to_read = 0;
108 if (escd_left_to_read == 0) *eof = 1;
109 n = min(count,escd_left_to_read);
110 memcpy(buf, tmpbuf + pos, n);
111 kfree(tmpbuf);
112 *start = buf;
113 return n;
114}
115
116static int proc_read_legacyres(char *buf, char **start, off_t pos,
117 int count, int *eof, void *data)
118{
119 /* Assume that the following won't overflow the buffer */
120 if (pnp_bios_get_stat_res(buf))
121 return -EIO;
122
123 return count; // FIXME: Return actual length
124}
125
126static int proc_read_devices(char *buf, char **start, off_t pos,
127 int count, int *eof, void *data)
128{
129 struct pnp_bios_node *node;
130 u8 nodenum;
131 char *p = buf;
132
133 if (pos >= 0xff)
134 return 0;
135
136 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
137 if (!node) return -ENOMEM;
138
139 for (nodenum=pos; nodenum<0xff; ) {
140 u8 thisnodenum = nodenum;
141 /* 26 = the number of characters per line sprintf'ed */
142 if ((p - buf + 26) > count)
143 break;
144 if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node))
145 break;
146 p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
147 node->handle, node->eisa_id,
148 node->type_code[0], node->type_code[1],
149 node->type_code[2], node->flags);
150 if (nodenum <= thisnodenum) {
151 printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
152 *eof = 1;
153 break;
154 }
155 }
156 kfree(node);
157 if (nodenum == 0xff)
158 *eof = 1;
159 *start = (char *)((off_t)nodenum - pos);
160 return p - buf;
161}
162
163static int proc_read_node(char *buf, char **start, off_t pos,
164 int count, int *eof, void *data)
165{
166 struct pnp_bios_node *node;
167 int boot = (long)data >> 8;
168 u8 nodenum = (long)data;
169 int len;
170
171 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
172 if (!node) return -ENOMEM;
173 if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
174 kfree(node);
175 return -EIO;
176 }
177 len = node->size - sizeof(struct pnp_bios_node);
178 memcpy(buf, node->data, len);
179 kfree(node);
180 return len;
181}
182
183static int proc_write_node(struct file *file, const char __user *buf,
184 unsigned long count, void *data)
185{
186 struct pnp_bios_node *node;
187 int boot = (long)data >> 8;
188 u8 nodenum = (long)data;
189 int ret = count;
190
191 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
192 if (!node)
193 return -ENOMEM;
194 if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
195 ret = -EIO;
196 goto out;
197 }
198 if (count != node->size - sizeof(struct pnp_bios_node)) {
199 ret = -EINVAL;
200 goto out;
201 }
202 if (copy_from_user(node->data, buf, count)) {
203 ret = -EFAULT;
204 goto out;
205 }
206 if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) {
207 ret = -EINVAL;
208 goto out;
209 }
210 ret = count;
211out:
212 kfree(node);
213 return ret;
214}
215
216int pnpbios_interface_attach_device(struct pnp_bios_node * node)
217{
218 char name[3];
219 struct proc_dir_entry *ent;
220
221 sprintf(name, "%02x", node->handle);
222
223 if (!proc_pnp)
224 return -EIO;
225 if ( !pnpbios_dont_use_current_config ) {
226 ent = create_proc_entry(name, 0, proc_pnp);
227 if (ent) {
228 ent->read_proc = proc_read_node;
229 ent->write_proc = proc_write_node;
230 ent->data = (void *)(long)(node->handle);
231 }
232 }
233
234 if (!proc_pnp_boot)
235 return -EIO;
236 ent = create_proc_entry(name, 0, proc_pnp_boot);
237 if (ent) {
238 ent->read_proc = proc_read_node;
239 ent->write_proc = proc_write_node;
240 ent->data = (void *)(long)(node->handle+0x100);
241 return 0;
242 }
243
244 return -EIO;
245}
246
247/*
248 * When this is called, pnpbios functions are assumed to
249 * work and the pnpbios_dont_use_current_config flag
250 * should already have been set to the appropriate value
251 */
252int __init pnpbios_proc_init( void )
253{
254 proc_pnp = proc_mkdir("pnp", proc_bus);
255 if (!proc_pnp)
256 return -EIO;
257 proc_pnp_boot = proc_mkdir("boot", proc_pnp);
258 if (!proc_pnp_boot)
259 return -EIO;
260 create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
261 create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
262 create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
263 create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
264 create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
265
266 return 0;
267}
268
269void __exit pnpbios_proc_exit(void)
270{
271 int i;
272 char name[3];
273
274 if (!proc_pnp)
275 return;
276
277 for (i=0; i<0xff; i++) {
278 sprintf(name, "%02x", i);
279 if ( !pnpbios_dont_use_current_config )
280 remove_proc_entry(name, proc_pnp);
281 remove_proc_entry(name, proc_pnp_boot);
282 }
283 remove_proc_entry("legacy_device_resources", proc_pnp);
284 remove_proc_entry("escd", proc_pnp);
285 remove_proc_entry("escd_info", proc_pnp);
286 remove_proc_entry("configuration_info", proc_pnp);
287 remove_proc_entry("devices", proc_pnp);
288 remove_proc_entry("boot", proc_pnp);
289 remove_proc_entry("pnp", proc_bus);
290
291 return;
292}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
new file mode 100644
index 000000000000..618ac15a9e90
--- /dev/null
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -0,0 +1,795 @@
1/*
2 * rsparser.c - parses and encodes pnpbios resource data streams
3 *
4 */
5
6#include <linux/config.h>
7#include <linux/ctype.h>
8#include <linux/pnp.h>
9#include <linux/pnpbios.h>
10
11#ifdef CONFIG_PCI
12#include <linux/pci.h>
13#else
14inline void pcibios_penalize_isa_irq(int irq) {}
15#endif /* CONFIG_PCI */
16
17#include "pnpbios.h"
18
19/* standard resource tags */
20#define SMALL_TAG_PNPVERNO 0x01
21#define SMALL_TAG_LOGDEVID 0x02
22#define SMALL_TAG_COMPATDEVID 0x03
23#define SMALL_TAG_IRQ 0x04
24#define SMALL_TAG_DMA 0x05
25#define SMALL_TAG_STARTDEP 0x06
26#define SMALL_TAG_ENDDEP 0x07
27#define SMALL_TAG_PORT 0x08
28#define SMALL_TAG_FIXEDPORT 0x09
29#define SMALL_TAG_VENDOR 0x0e
30#define SMALL_TAG_END 0x0f
31#define LARGE_TAG 0x80
32#define LARGE_TAG_MEM 0x81
33#define LARGE_TAG_ANSISTR 0x82
34#define LARGE_TAG_UNICODESTR 0x83
35#define LARGE_TAG_VENDOR 0x84
36#define LARGE_TAG_MEM32 0x85
37#define LARGE_TAG_FIXEDMEM32 0x86
38
39/*
40 * Resource Data Stream Format:
41 *
42 * Allocated Resources (required)
43 * end tag ->
44 * Resource Configuration Options (optional)
45 * end tag ->
46 * Compitable Device IDs (optional)
47 * final end tag ->
48 */
49
50/*
51 * Allocated Resources
52 */
53
54static void
55pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
56{
57 int i = 0;
58 while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_IRQ) i++;
59 if (i < PNP_MAX_IRQ) {
60 res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
61 if (irq == -1) {
62 res->irq_resource[i].flags |= IORESOURCE_DISABLED;
63 return;
64 }
65 res->irq_resource[i].start =
66 res->irq_resource[i].end = (unsigned long) irq;
67 pcibios_penalize_isa_irq(irq);
68 }
69}
70
71static void
72pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
73{
74 int i = 0;
75 while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_DMA) i++;
76 if (i < PNP_MAX_DMA) {
77 res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
78 if (dma == -1) {
79 res->dma_resource[i].flags |= IORESOURCE_DISABLED;
80 return;
81 }
82 res->dma_resource[i].start =
83 res->dma_resource[i].end = (unsigned long) dma;
84 }
85}
86
87static void
88pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len)
89{
90 int i = 0;
91 while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_PORT) i++;
92 if (i < PNP_MAX_PORT) {
93 res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
94 if (len <= 0 || (io + len -1) >= 0x10003) {
95 res->port_resource[i].flags |= IORESOURCE_DISABLED;
96 return;
97 }
98 res->port_resource[i].start = (unsigned long) io;
99 res->port_resource[i].end = (unsigned long)(io + len - 1);
100 }
101}
102
103static void
104pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len)
105{
106 int i = 0;
107 while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_MEM) i++;
108 if (i < PNP_MAX_MEM) {
109 res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
110 if (len <= 0) {
111 res->mem_resource[i].flags |= IORESOURCE_DISABLED;
112 return;
113 }
114 res->mem_resource[i].start = (unsigned long) mem;
115 res->mem_resource[i].end = (unsigned long)(mem + len - 1);
116 }
117}
118
119static unsigned char *
120pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
121{
122 unsigned int len, tag;
123 int io, size, mask, i;
124
125 if (!p)
126 return NULL;
127
128 /* Blank the resource table values */
129 pnp_init_resource_table(res);
130
131 while ((char *)p < (char *)end) {
132
133 /* determine the type of tag */
134 if (p[0] & LARGE_TAG) { /* large tag */
135 len = (p[2] << 8) | p[1];
136 tag = p[0];
137 } else { /* small tag */
138 len = p[0] & 0x07;
139 tag = ((p[0]>>3) & 0x0f);
140 }
141
142 switch (tag) {
143
144 case LARGE_TAG_MEM:
145 if (len != 9)
146 goto len_err;
147 io = *(short *) &p[4];
148 size = *(short *) &p[10];
149 pnpbios_parse_allocated_memresource(res, io, size);
150 break;
151
152 case LARGE_TAG_ANSISTR:
153 /* ignore this for now */
154 break;
155
156 case LARGE_TAG_VENDOR:
157 /* do nothing */
158 break;
159
160 case LARGE_TAG_MEM32:
161 if (len != 17)
162 goto len_err;
163 io = *(int *) &p[4];
164 size = *(int *) &p[16];
165 pnpbios_parse_allocated_memresource(res, io, size);
166 break;
167
168 case LARGE_TAG_FIXEDMEM32:
169 if (len != 9)
170 goto len_err;
171 io = *(int *) &p[4];
172 size = *(int *) &p[8];
173 pnpbios_parse_allocated_memresource(res, io, size);
174 break;
175
176 case SMALL_TAG_IRQ:
177 if (len < 2 || len > 3)
178 goto len_err;
179 io = -1;
180 mask= p[1] + p[2]*256;
181 for (i=0;i<16;i++, mask=mask>>1)
182 if(mask & 0x01) io=i;
183 pnpbios_parse_allocated_irqresource(res, io);
184 break;
185
186 case SMALL_TAG_DMA:
187 if (len != 2)
188 goto len_err;
189 io = -1;
190 mask = p[1];
191 for (i=0;i<8;i++, mask = mask>>1)
192 if(mask & 0x01) io=i;
193 pnpbios_parse_allocated_dmaresource(res, io);
194 break;
195
196 case SMALL_TAG_PORT:
197 if (len != 7)
198 goto len_err;
199 io = p[2] + p[3] *256;
200 size = p[7];
201 pnpbios_parse_allocated_ioresource(res, io, size);
202 break;
203
204 case SMALL_TAG_VENDOR:
205 /* do nothing */
206 break;
207
208 case SMALL_TAG_FIXEDPORT:
209 if (len != 3)
210 goto len_err;
211 io = p[1] + p[2] * 256;
212 size = p[3];
213 pnpbios_parse_allocated_ioresource(res, io, size);
214 break;
215
216 case SMALL_TAG_END:
217 p = p + 2;
218 return (unsigned char *)p;
219 break;
220
221 default: /* an unkown tag */
222 len_err:
223 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
224 break;
225 }
226
227 /* continue to the next tag */
228 if (p[0] & LARGE_TAG)
229 p += len + 3;
230 else
231 p += len + 1;
232 }
233
234 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
235
236 return NULL;
237}
238
239
240/*
241 * Resource Configuration Options
242 */
243
244static void
245pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
246{
247 struct pnp_mem * mem;
248 mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
249 if (!mem)
250 return;
251 mem->min = ((p[5] << 8) | p[4]) << 8;
252 mem->max = ((p[7] << 8) | p[6]) << 8;
253 mem->align = (p[9] << 8) | p[8];
254 mem->size = ((p[11] << 8) | p[10]) << 8;
255 mem->flags = p[3];
256 pnp_register_mem_resource(option,mem);
257 return;
258}
259
260static void
261pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
262{
263 struct pnp_mem * mem;
264 mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
265 if (!mem)
266 return;
267 mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
268 mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
269 mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
270 mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
271 mem->flags = p[3];
272 pnp_register_mem_resource(option,mem);
273 return;
274}
275
276static void
277pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
278{
279 struct pnp_mem * mem;
280 mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
281 if (!mem)
282 return;
283 mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
284 mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
285 mem->align = 0;
286 mem->flags = p[3];
287 pnp_register_mem_resource(option,mem);
288 return;
289}
290
291static void
292pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
293{
294 struct pnp_irq * irq;
295 unsigned long bits;
296
297 irq = pnpbios_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
298 if (!irq)
299 return;
300 bits = (p[2] << 8) | p[1];
301 bitmap_copy(irq->map, &bits, 16);
302 if (size > 2)
303 irq->flags = p[3];
304 else
305 irq->flags = IORESOURCE_IRQ_HIGHEDGE;
306 pnp_register_irq_resource(option,irq);
307 return;
308}
309
310static void
311pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
312{
313 struct pnp_dma * dma;
314 dma = pnpbios_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
315 if (!dma)
316 return;
317 dma->map = p[1];
318 dma->flags = p[2];
319 pnp_register_dma_resource(option,dma);
320 return;
321}
322
323static void
324pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
325{
326 struct pnp_port * port;
327 port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
328 if (!port)
329 return;
330 port->min = (p[3] << 8) | p[2];
331 port->max = (p[5] << 8) | p[4];
332 port->align = p[6];
333 port->size = p[7];
334 port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
335 pnp_register_port_resource(option,port);
336 return;
337}
338
339static void
340pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
341{
342 struct pnp_port * port;
343 port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
344 if (!port)
345 return;
346 port->min = port->max = (p[2] << 8) | p[1];
347 port->size = p[3];
348 port->align = 0;
349 port->flags = PNP_PORT_FLAG_FIXED;
350 pnp_register_port_resource(option,port);
351 return;
352}
353
354static unsigned char *
355pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
356{
357 unsigned int len, tag;
358 int priority = 0;
359 struct pnp_option *option, *option_independent;
360
361 if (!p)
362 return NULL;
363
364 option_independent = option = pnp_register_independent_option(dev);
365 if (!option)
366 return NULL;
367
368 while ((char *)p < (char *)end) {
369
370 /* determine the type of tag */
371 if (p[0] & LARGE_TAG) { /* large tag */
372 len = (p[2] << 8) | p[1];
373 tag = p[0];
374 } else { /* small tag */
375 len = p[0] & 0x07;
376 tag = ((p[0]>>3) & 0x0f);
377 }
378
379 switch (tag) {
380
381 case LARGE_TAG_MEM:
382 if (len != 9)
383 goto len_err;
384 pnpbios_parse_mem_option(p, len, option);
385 break;
386
387 case LARGE_TAG_MEM32:
388 if (len != 17)
389 goto len_err;
390 pnpbios_parse_mem32_option(p, len, option);
391 break;
392
393 case LARGE_TAG_FIXEDMEM32:
394 if (len != 9)
395 goto len_err;
396 pnpbios_parse_fixed_mem32_option(p, len, option);
397 break;
398
399 case SMALL_TAG_IRQ:
400 if (len < 2 || len > 3)
401 goto len_err;
402 pnpbios_parse_irq_option(p, len, option);
403 break;
404
405 case SMALL_TAG_DMA:
406 if (len != 2)
407 goto len_err;
408 pnpbios_parse_dma_option(p, len, option);
409 break;
410
411 case SMALL_TAG_PORT:
412 if (len != 7)
413 goto len_err;
414 pnpbios_parse_port_option(p, len, option);
415 break;
416
417 case SMALL_TAG_VENDOR:
418 /* do nothing */
419 break;
420
421 case SMALL_TAG_FIXEDPORT:
422 if (len != 3)
423 goto len_err;
424 pnpbios_parse_fixed_port_option(p, len, option);
425 break;
426
427 case SMALL_TAG_STARTDEP:
428 if (len > 1)
429 goto len_err;
430 priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
431 if (len > 0)
432 priority = 0x100 | p[1];
433 option = pnp_register_dependent_option(dev, priority);
434 if (!option)
435 return NULL;
436 break;
437
438 case SMALL_TAG_ENDDEP:
439 if (len != 0)
440 goto len_err;
441 if (option_independent == option)
442 printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
443 option = option_independent;
444 break;
445
446 case SMALL_TAG_END:
447 if (option_independent != option)
448 printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_ENDDEP tag\n");
449 p = p + 2;
450 return (unsigned char *)p;
451 break;
452
453 default: /* an unkown tag */
454 len_err:
455 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
456 break;
457 }
458
459 /* continue to the next tag */
460 if (p[0] & LARGE_TAG)
461 p += len + 3;
462 else
463 p += len + 1;
464 }
465
466 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
467
468 return NULL;
469}
470
471
472/*
473 * Compatible Device IDs
474 */
475
476#define HEX(id,a) hex[((id)>>a) & 15]
477#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
478//
479
480void pnpid32_to_pnpid(u32 id, char *str)
481{
482 const char *hex = "0123456789abcdef";
483
484 id = be32_to_cpu(id);
485 str[0] = CHAR(id, 26);
486 str[1] = CHAR(id, 21);
487 str[2] = CHAR(id,16);
488 str[3] = HEX(id, 12);
489 str[4] = HEX(id, 8);
490 str[5] = HEX(id, 4);
491 str[6] = HEX(id, 0);
492 str[7] = '\0';
493
494 return;
495}
496//
497#undef CHAR
498#undef HEX
499
500static unsigned char *
501pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev)
502{
503 int len, tag;
504 char id[8];
505 struct pnp_id *dev_id;
506
507 if (!p)
508 return NULL;
509
510 while ((char *)p < (char *)end) {
511
512 /* determine the type of tag */
513 if (p[0] & LARGE_TAG) { /* large tag */
514 len = (p[2] << 8) | p[1];
515 tag = p[0];
516 } else { /* small tag */
517 len = p[0] & 0x07;
518 tag = ((p[0]>>3) & 0x0f);
519 }
520
521 switch (tag) {
522
523 case LARGE_TAG_ANSISTR:
524 strncpy(dev->name, p + 3, len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
525 dev->name[len >= PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
526 break;
527
528 case SMALL_TAG_COMPATDEVID: /* compatible ID */
529 if (len != 4)
530 goto len_err;
531 dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
532 if (!dev_id)
533 return NULL;
534 memset(dev_id, 0, sizeof(struct pnp_id));
535 pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
536 memcpy(&dev_id->id, id, 7);
537 pnp_add_id(dev_id, dev);
538 break;
539
540 case SMALL_TAG_END:
541 p = p + 2;
542 return (unsigned char *)p;
543 break;
544
545 default: /* an unkown tag */
546 len_err:
547 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
548 break;
549 }
550
551 /* continue to the next tag */
552 if (p[0] & LARGE_TAG)
553 p += len + 3;
554 else
555 p += len + 1;
556 }
557
558 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
559
560 return NULL;
561}
562
563
564/*
565 * Allocated Resource Encoding
566 */
567
568static void pnpbios_encode_mem(unsigned char *p, struct resource * res)
569{
570 unsigned long base = res->start;
571 unsigned long len = res->end - res->start + 1;
572 p[4] = (base >> 8) & 0xff;
573 p[5] = ((base >> 8) >> 8) & 0xff;
574 p[6] = (base >> 8) & 0xff;
575 p[7] = ((base >> 8) >> 8) & 0xff;
576 p[10] = (len >> 8) & 0xff;
577 p[11] = ((len >> 8) >> 8) & 0xff;
578 return;
579}
580
581static void pnpbios_encode_mem32(unsigned char *p, struct resource * res)
582{
583 unsigned long base = res->start;
584 unsigned long len = res->end - res->start + 1;
585 p[4] = base & 0xff;
586 p[5] = (base >> 8) & 0xff;
587 p[6] = (base >> 16) & 0xff;
588 p[7] = (base >> 24) & 0xff;
589 p[8] = base & 0xff;
590 p[9] = (base >> 8) & 0xff;
591 p[10] = (base >> 16) & 0xff;
592 p[11] = (base >> 24) & 0xff;
593 p[16] = len & 0xff;
594 p[17] = (len >> 8) & 0xff;
595 p[18] = (len >> 16) & 0xff;
596 p[19] = (len >> 24) & 0xff;
597 return;
598}
599
600static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource * res)
601{ unsigned long base = res->start;
602 unsigned long len = res->end - res->start + 1;
603 p[4] = base & 0xff;
604 p[5] = (base >> 8) & 0xff;
605 p[6] = (base >> 16) & 0xff;
606 p[7] = (base >> 24) & 0xff;
607 p[8] = len & 0xff;
608 p[9] = (len >> 8) & 0xff;
609 p[10] = (len >> 16) & 0xff;
610 p[11] = (len >> 24) & 0xff;
611 return;
612}
613
614static void pnpbios_encode_irq(unsigned char *p, struct resource * res)
615{
616 unsigned long map = 0;
617 map = 1 << res->start;
618 p[1] = map & 0xff;
619 p[2] = (map >> 8) & 0xff;
620 return;
621}
622
623static void pnpbios_encode_dma(unsigned char *p, struct resource * res)
624{
625 unsigned long map = 0;
626 map = 1 << res->start;
627 p[1] = map & 0xff;
628 return;
629}
630
631static void pnpbios_encode_port(unsigned char *p, struct resource * res)
632{
633 unsigned long base = res->start;
634 unsigned long len = res->end - res->start + 1;
635 p[2] = base & 0xff;
636 p[3] = (base >> 8) & 0xff;
637 p[4] = base & 0xff;
638 p[5] = (base >> 8) & 0xff;
639 p[7] = len & 0xff;
640 return;
641}
642
643static void pnpbios_encode_fixed_port(unsigned char *p, struct resource * res)
644{
645 unsigned long base = res->start;
646 unsigned long len = res->end - res->start + 1;
647 p[1] = base & 0xff;
648 p[2] = (base >> 8) & 0xff;
649 p[3] = len & 0xff;
650 return;
651}
652
653static unsigned char *
654pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
655{
656 unsigned int len, tag;
657 int port = 0, irq = 0, dma = 0, mem = 0;
658
659 if (!p)
660 return NULL;
661
662 while ((char *)p < (char *)end) {
663
664 /* determine the type of tag */
665 if (p[0] & LARGE_TAG) { /* large tag */
666 len = (p[2] << 8) | p[1];
667 tag = p[0];
668 } else { /* small tag */
669 len = p[0] & 0x07;
670 tag = ((p[0]>>3) & 0x0f);
671 }
672
673 switch (tag) {
674
675 case LARGE_TAG_MEM:
676 if (len != 9)
677 goto len_err;
678 pnpbios_encode_mem(p, &res->mem_resource[mem]);
679 mem++;
680 break;
681
682 case LARGE_TAG_MEM32:
683 if (len != 17)
684 goto len_err;
685 pnpbios_encode_mem32(p, &res->mem_resource[mem]);
686 mem++;
687 break;
688
689 case LARGE_TAG_FIXEDMEM32:
690 if (len != 9)
691 goto len_err;
692 pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]);
693 mem++;
694 break;
695
696 case SMALL_TAG_IRQ:
697 if (len < 2 || len > 3)
698 goto len_err;
699 pnpbios_encode_irq(p, &res->irq_resource[irq]);
700 irq++;
701 break;
702
703 case SMALL_TAG_DMA:
704 if (len != 2)
705 goto len_err;
706 pnpbios_encode_dma(p, &res->dma_resource[dma]);
707 dma++;
708 break;
709
710 case SMALL_TAG_PORT:
711 if (len != 7)
712 goto len_err;
713 pnpbios_encode_port(p, &res->port_resource[port]);
714 port++;
715 break;
716
717 case SMALL_TAG_VENDOR:
718 /* do nothing */
719 break;
720
721 case SMALL_TAG_FIXEDPORT:
722 if (len != 3)
723 goto len_err;
724 pnpbios_encode_fixed_port(p, &res->port_resource[port]);
725 port++;
726 break;
727
728 case SMALL_TAG_END:
729 p = p + 2;
730 return (unsigned char *)p;
731 break;
732
733 default: /* an unkown tag */
734 len_err:
735 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
736 break;
737 }
738
739 /* continue to the next tag */
740 if (p[0] & LARGE_TAG)
741 p += len + 3;
742 else
743 p += len + 1;
744 }
745
746 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
747
748 return NULL;
749}
750
751
752/*
753 * Core Parsing Functions
754 */
755
756int
757pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node)
758{
759 unsigned char * p = (char *)node->data;
760 unsigned char * end = (char *)(node->data + node->size);
761 p = pnpbios_parse_allocated_resource_data(p,end,&dev->res);
762 if (!p)
763 return -EIO;
764 p = pnpbios_parse_resource_option_data(p,end,dev);
765 if (!p)
766 return -EIO;
767 p = pnpbios_parse_compatible_ids(p,end,dev);
768 if (!p)
769 return -EIO;
770 return 0;
771}
772
773int
774pnpbios_read_resources_from_node(struct pnp_resource_table *res,
775 struct pnp_bios_node * node)
776{
777 unsigned char * p = (char *)node->data;
778 unsigned char * end = (char *)(node->data + node->size);
779 p = pnpbios_parse_allocated_resource_data(p,end,res);
780 if (!p)
781 return -EIO;
782 return 0;
783}
784
785int
786pnpbios_write_resources_to_node(struct pnp_resource_table *res,
787 struct pnp_bios_node * node)
788{
789 unsigned char * p = (char *)node->data;
790 unsigned char * end = (char *)(node->data + node->size);
791 p = pnpbios_encode_allocated_resource_data(p,end,res);
792 if (!p)
793 return -EIO;
794 return 0;
795}