PNP: Lindent all source files
[linux-2.6.git] / drivers / pnp / pnpbios / proc.c
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
36 static struct proc_dir_entry *proc_pnp = NULL;
37 static struct proc_dir_entry *proc_pnp_boot = NULL;
38
39 static 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, pnps.no_csns, pnps.isa_rd_data_port);
51 }
52
53 static int proc_read_escdinfo(char *buf, char **start, off_t pos,
54                               int count, int *eof, void *data)
55 {
56         struct escd_info_struc escd;
57
58         if (pnp_bios_escd_info(&escd))
59                 return -EIO;
60         return snprintf(buf, count,
61                         "min_ESCD_write_size %d\n"
62                         "ESCD_size %d\n"
63                         "NVRAM_base 0x%x\n",
64                         escd.min_escd_write_size,
65                         escd.escd_size, escd.nv_storage_base);
66 }
67
68 #define MAX_SANE_ESCD_SIZE (32*1024)
69 static int proc_read_escd(char *buf, char **start, off_t pos,
70                           int count, int *eof, void *data)
71 {
72         struct escd_info_struc escd;
73         char *tmpbuf;
74         int escd_size, escd_left_to_read, n;
75
76         if (pnp_bios_escd_info(&escd))
77                 return -EIO;
78
79         /* sanity check */
80         if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
81                 printk(KERN_ERR
82                        "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
83                 return -EFBIG;
84         }
85
86         tmpbuf = kzalloc(escd.escd_size, GFP_KERNEL);
87         if (!tmpbuf)
88                 return -ENOMEM;
89
90         if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
91                 kfree(tmpbuf);
92                 return -EIO;
93         }
94
95         escd_size =
96             (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1]) * 256;
97
98         /* sanity check */
99         if (escd_size > MAX_SANE_ESCD_SIZE) {
100                 printk(KERN_ERR
101                        "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
102                 return -EFBIG;
103         }
104
105         escd_left_to_read = escd_size - pos;
106         if (escd_left_to_read < 0)
107                 escd_left_to_read = 0;
108         if (escd_left_to_read == 0)
109                 *eof = 1;
110         n = min(count, escd_left_to_read);
111         memcpy(buf, tmpbuf + pos, n);
112         kfree(tmpbuf);
113         *start = buf;
114         return n;
115 }
116
117 static int proc_read_legacyres(char *buf, char **start, off_t pos,
118                                int count, int *eof, void *data)
119 {
120         /* Assume that the following won't overflow the buffer */
121         if (pnp_bios_get_stat_res(buf))
122                 return -EIO;
123
124         return count;           // FIXME: Return actual length
125 }
126
127 static int proc_read_devices(char *buf, char **start, off_t pos,
128                              int count, int *eof, void *data)
129 {
130         struct pnp_bios_node *node;
131         u8 nodenum;
132         char *p = buf;
133
134         if (pos >= 0xff)
135                 return 0;
136
137         node = kzalloc(node_info.max_node_size, GFP_KERNEL);
138         if (!node)
139                 return -ENOMEM;
140
141         for (nodenum = pos; nodenum < 0xff;) {
142                 u8 thisnodenum = nodenum;
143                 /* 26 = the number of characters per line sprintf'ed */
144                 if ((p - buf + 26) > count)
145                         break;
146                 if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node))
147                         break;
148                 p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
149                              node->handle, node->eisa_id,
150                              node->type_code[0], node->type_code[1],
151                              node->type_code[2], node->flags);
152                 if (nodenum <= thisnodenum) {
153                         printk(KERN_ERR
154                                "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
155                                "PnPBIOS: proc_read_devices:",
156                                (unsigned int)nodenum,
157                                (unsigned int)thisnodenum);
158                         *eof = 1;
159                         break;
160                 }
161         }
162         kfree(node);
163         if (nodenum == 0xff)
164                 *eof = 1;
165         *start = (char *)((off_t) nodenum - pos);
166         return p - buf;
167 }
168
169 static int proc_read_node(char *buf, char **start, off_t pos,
170                           int count, int *eof, void *data)
171 {
172         struct pnp_bios_node *node;
173         int boot = (long)data >> 8;
174         u8 nodenum = (long)data;
175         int len;
176
177         node = kzalloc(node_info.max_node_size, GFP_KERNEL);
178         if (!node)
179                 return -ENOMEM;
180         if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
181                 kfree(node);
182                 return -EIO;
183         }
184         len = node->size - sizeof(struct pnp_bios_node);
185         memcpy(buf, node->data, len);
186         kfree(node);
187         return len;
188 }
189
190 static int proc_write_node(struct file *file, const char __user * buf,
191                            unsigned long count, void *data)
192 {
193         struct pnp_bios_node *node;
194         int boot = (long)data >> 8;
195         u8 nodenum = (long)data;
196         int ret = count;
197
198         node = kzalloc(node_info.max_node_size, GFP_KERNEL);
199         if (!node)
200                 return -ENOMEM;
201         if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
202                 ret = -EIO;
203                 goto out;
204         }
205         if (count != node->size - sizeof(struct pnp_bios_node)) {
206                 ret = -EINVAL;
207                 goto out;
208         }
209         if (copy_from_user(node->data, buf, count)) {
210                 ret = -EFAULT;
211                 goto out;
212         }
213         if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) {
214                 ret = -EINVAL;
215                 goto out;
216         }
217         ret = count;
218       out:
219         kfree(node);
220         return ret;
221 }
222
223 int pnpbios_interface_attach_device(struct pnp_bios_node *node)
224 {
225         char name[3];
226         struct proc_dir_entry *ent;
227
228         sprintf(name, "%02x", node->handle);
229
230         if (!proc_pnp)
231                 return -EIO;
232         if (!pnpbios_dont_use_current_config) {
233                 ent = create_proc_entry(name, 0, proc_pnp);
234                 if (ent) {
235                         ent->read_proc = proc_read_node;
236                         ent->write_proc = proc_write_node;
237                         ent->data = (void *)(long)(node->handle);
238                 }
239         }
240
241         if (!proc_pnp_boot)
242                 return -EIO;
243         ent = create_proc_entry(name, 0, proc_pnp_boot);
244         if (ent) {
245                 ent->read_proc = proc_read_node;
246                 ent->write_proc = proc_write_node;
247                 ent->data = (void *)(long)(node->handle + 0x100);
248                 return 0;
249         }
250
251         return -EIO;
252 }
253
254 /*
255  * When this is called, pnpbios functions are assumed to
256  * work and the pnpbios_dont_use_current_config flag
257  * should already have been set to the appropriate value
258  */
259 int __init pnpbios_proc_init(void)
260 {
261         proc_pnp = proc_mkdir("pnp", proc_bus);
262         if (!proc_pnp)
263                 return -EIO;
264         proc_pnp_boot = proc_mkdir("boot", proc_pnp);
265         if (!proc_pnp_boot)
266                 return -EIO;
267         create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
268         create_proc_read_entry("configuration_info", 0, proc_pnp,
269                                proc_read_pnpconfig, NULL);
270         create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo,
271                                NULL);
272         create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
273         create_proc_read_entry("legacy_device_resources", 0, proc_pnp,
274                                proc_read_legacyres, NULL);
275
276         return 0;
277 }
278
279 void __exit pnpbios_proc_exit(void)
280 {
281         int i;
282         char name[3];
283
284         if (!proc_pnp)
285                 return;
286
287         for (i = 0; i < 0xff; i++) {
288                 sprintf(name, "%02x", i);
289                 if (!pnpbios_dont_use_current_config)
290                         remove_proc_entry(name, proc_pnp);
291                 remove_proc_entry(name, proc_pnp_boot);
292         }
293         remove_proc_entry("legacy_device_resources", proc_pnp);
294         remove_proc_entry("escd", proc_pnp);
295         remove_proc_entry("escd_info", proc_pnp);
296         remove_proc_entry("configuration_info", proc_pnp);
297         remove_proc_entry("devices", proc_pnp);
298         remove_proc_entry("boot", proc_pnp);
299         remove_proc_entry("pnp", proc_bus);
300
301         return;
302 }