2 * /proc/bus/pnp interface for Plug and Play devices
4 * Written by David Hinds, dahinds@users.sourceforge.net
5 * Modified by Thomas Hood
7 * The .../devices and .../<node> and .../boot/<node> files are
8 * utilized by the lspnp and setpnp utilities, supplied with the
10 * http://pcmcia-cs.sourceforge.net
12 * The .../escd file is utilized by the lsescd utility written by
14 * http://home.t-online.de/home/gunther.mayer/lsescd
16 * The .../legacy_device_resources file is not used yet.
18 * The other files are human-readable.
21 //#include <pcmcia/config.h>
22 //#include <pcmcia/k_compat.h>
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>
32 #include <asm/uaccess.h>
36 static struct proc_dir_entry
*proc_pnp
= NULL
;
37 static struct proc_dir_entry
*proc_pnp_boot
= NULL
;
39 static int proc_read_pnpconfig(char *buf
, char **start
, off_t pos
,
40 int count
, int *eof
, void *data
)
42 struct pnp_isa_config_struc pnps
;
44 if (pnp_bios_isapnp_config(&pnps
))
46 return snprintf(buf
, count
,
47 "structure_revision %d\n"
49 "ISA_read_data_port 0x%x\n",
56 static int proc_read_escdinfo(char *buf
, char **start
, off_t pos
,
57 int count
, int *eof
, void *data
)
59 struct escd_info_struc escd
;
61 if (pnp_bios_escd_info(&escd
))
63 return snprintf(buf
, count
,
64 "min_ESCD_write_size %d\n"
67 escd
.min_escd_write_size
,
73 #define MAX_SANE_ESCD_SIZE (32*1024)
74 static int proc_read_escd(char *buf
, char **start
, off_t pos
,
75 int count
, int *eof
, void *data
)
77 struct escd_info_struc escd
;
79 int escd_size
, escd_left_to_read
, n
;
81 if (pnp_bios_escd_info(&escd
))
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");
90 tmpbuf
= pnpbios_kmalloc(escd
.escd_size
, GFP_KERNEL
);
91 if (!tmpbuf
) return -ENOMEM
;
93 if (pnp_bios_read_escd(tmpbuf
, escd
.nv_storage_base
)) {
98 escd_size
= (unsigned char)(tmpbuf
[0]) + (unsigned char)(tmpbuf
[1])*256;
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");
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
);
116 static int proc_read_legacyres(char *buf
, char **start
, off_t pos
,
117 int count
, int *eof
, void *data
)
119 /* Assume that the following won't overflow the buffer */
120 if (pnp_bios_get_stat_res(buf
))
123 return count
; // FIXME: Return actual length
126 static int proc_read_devices(char *buf
, char **start
, off_t pos
,
127 int count
, int *eof
, void *data
)
129 struct pnp_bios_node
*node
;
136 node
= pnpbios_kmalloc(node_info
.max_node_size
, GFP_KERNEL
);
137 if (!node
) return -ENOMEM
;
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
)
144 if (pnp_bios_get_dev_node(&nodenum
, PNPMODE_DYNAMIC
, node
))
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
);
159 *start
= (char *)((off_t
)nodenum
- pos
);
163 static int proc_read_node(char *buf
, char **start
, off_t pos
,
164 int count
, int *eof
, void *data
)
166 struct pnp_bios_node
*node
;
167 int boot
= (long)data
>> 8;
168 u8 nodenum
= (long)data
;
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
)) {
177 len
= node
->size
- sizeof(struct pnp_bios_node
);
178 memcpy(buf
, node
->data
, len
);
183 static int proc_write_node(struct file
*file
, const char __user
*buf
,
184 unsigned long count
, void *data
)
186 struct pnp_bios_node
*node
;
187 int boot
= (long)data
>> 8;
188 u8 nodenum
= (long)data
;
191 node
= pnpbios_kmalloc(node_info
.max_node_size
, GFP_KERNEL
);
194 if (pnp_bios_get_dev_node(&nodenum
, boot
, node
)) {
198 if (count
!= node
->size
- sizeof(struct pnp_bios_node
)) {
202 if (copy_from_user(node
->data
, buf
, count
)) {
206 if (pnp_bios_set_dev_node(node
->handle
, boot
, node
) != 0) {
216 int pnpbios_interface_attach_device(struct pnp_bios_node
* node
)
219 struct proc_dir_entry
*ent
;
221 sprintf(name
, "%02x", node
->handle
);
225 if ( !pnpbios_dont_use_current_config
) {
226 ent
= create_proc_entry(name
, 0, proc_pnp
);
228 ent
->read_proc
= proc_read_node
;
229 ent
->write_proc
= proc_write_node
;
230 ent
->data
= (void *)(long)(node
->handle
);
236 ent
= create_proc_entry(name
, 0, proc_pnp_boot
);
238 ent
->read_proc
= proc_read_node
;
239 ent
->write_proc
= proc_write_node
;
240 ent
->data
= (void *)(long)(node
->handle
+0x100);
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
252 int __init
pnpbios_proc_init( void )
254 proc_pnp
= proc_mkdir("pnp", proc_bus
);
257 proc_pnp_boot
= proc_mkdir("boot", proc_pnp
);
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
);
269 void __exit
pnpbios_proc_exit(void)
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
);
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
);