1 /* $Id: openpromfs.c,v 1.36 1999/08/31 07:01:03 davem Exp $
2 * openpromfs.c: /proc/openprom handling routines
4 * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/string.h>
12 #include <linux/proc_fs.h>
13 #include <linux/init.h>
15 #include <asm/openprom.h>
16 #include <asm/oplib.h>
17 #include <asm/uaccess.h>
19 #define ALIASES_NNODES 64
30 #define OPP_STRING 0x10
31 #define OPP_STRINGLIST 0x20
32 #define OPP_BINARY 0x40
33 #define OPP_HEXSTRING 0x80
34 #define OPP_DIRTY 0x01
35 #define OPP_QUOTED 0x02
36 #define OPP_NOTQUOTED 0x04
37 #define OPP_ASCIIZ 0x08
45 static openpromfs_node
*nodes
= NULL
;
46 static int alloced
= 0;
47 static u16 last_node
= 0;
48 static u16 first_prop
= 0;
49 static u16 options
= 0xffff;
50 static u16 aliases
= 0xffff;
51 static int aliases_nodes
= 0;
52 static char *alias_names
[ALIASES_NNODES
];
53 static struct inode_operations
*proc_openprom_iops
= 0;
54 static struct openpromfs_dev
**devices
;
56 #define NODE(ino) nodes[ino - PROC_OPENPROM_FIRST]
57 #define NODE2INO(node) (node + PROC_OPENPROM_FIRST)
58 #define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
60 static int openpromfs_create (struct inode
*, struct dentry
*, int);
61 static int openpromfs_readdir(struct file
*, void *, filldir_t
);
62 static struct dentry
*openpromfs_lookup(struct inode
*, struct dentry
*dentry
);
63 static int openpromfs_unlink (struct inode
*, struct dentry
*dentry
);
65 static ssize_t
nodenum_read(struct file
*file
, char *buf
,
66 size_t count
, loff_t
*ppos
)
68 struct inode
*inode
= file
->f_dentry
->d_inode
;
71 if (count
< 0 || !inode
->u
.generic_ip
)
73 sprintf (buffer
, "%8.8x\n", (u32
)(long)(inode
->u
.generic_ip
));
76 if (count
> 9 - file
->f_pos
)
77 count
= 9 - file
->f_pos
;
78 copy_to_user(buf
, buffer
+ file
->f_pos
, count
);
83 static ssize_t
property_read(struct file
*filp
, char *buf
,
84 size_t count
, loff_t
*ppos
)
86 struct inode
*inode
= filp
->f_dentry
->d_inode
;
91 openprom_property
*op
;
94 if (filp
->f_pos
>= 0xffffff)
96 if (!filp
->private_data
) {
97 node
= nodes
[(u16
)((long)inode
->u
.generic_ip
)].node
;
98 i
= ((u32
)(long)inode
->u
.generic_ip
) >> 16;
99 if ((u16
)((long)inode
->u
.generic_ip
) == aliases
) {
100 if (i
>= aliases_nodes
)
105 for (p
= prom_firstprop (node
, buffer
);
107 p
= prom_nextprop (node
, p
, buffer
), i
--)
111 i
= prom_getproplen (node
, p
);
113 if ((u16
)((long)inode
->u
.generic_ip
) == aliases
)
120 filp
->private_data
= kmalloc (sizeof (openprom_property
)
121 + (j
= strlen (p
)) + 2 * i
,
123 if (!filp
->private_data
)
125 op
= (openprom_property
*)filp
->private_data
;
127 op
->alloclen
= 2 * i
;
128 strcpy (op
->name
, p
);
129 op
->value
= (char *)(((unsigned long)(op
->name
+ j
+ 4)) & ~3);
131 if (k
&& prom_getproperty (node
, p
, op
->value
, i
) < 0)
135 for (s
= 0, p
= op
->value
; p
< op
->value
+ k
; p
++) {
136 if ((*p
>= ' ' && *p
<= '~') || *p
== '\n') {
137 op
->flag
|= OPP_STRING
;
141 if (p
> op
->value
&& !*p
&& s
== p
- 1) {
142 if (p
< op
->value
+ k
- 1)
143 op
->flag
|= OPP_STRINGLIST
;
145 op
->flag
|= OPP_ASCIIZ
;
149 op
->flag
|= (OPP_STRING
|OPP_ASCIIZ
);
152 op
->flag
&= ~(OPP_STRING
|OPP_STRINGLIST
);
154 op
->flag
|= OPP_HEXSTRING
;
156 op
->flag
|= OPP_BINARY
;
159 if (op
->flag
& OPP_STRINGLIST
)
160 op
->flag
&= ~(OPP_STRING
);
161 if (op
->flag
& OPP_ASCIIZ
)
165 op
= (openprom_property
*)filp
->private_data
;
166 if (!count
|| !(op
->len
|| (op
->flag
& OPP_ASCIIZ
)))
168 if (op
->flag
& OPP_STRINGLIST
) {
169 for (k
= 0, p
= op
->value
; p
< op
->value
+ op
->len
; p
++)
172 i
= op
->len
+ 4 * k
+ 3;
173 } else if (op
->flag
& OPP_STRING
) {
175 } else if (op
->flag
& OPP_BINARY
) {
176 i
= (op
->len
* 9) >> 2;
178 i
= (op
->len
<< 1) + 1;
181 if (k
>= i
) return 0;
182 if (count
> i
- k
) count
= i
- k
;
183 if (op
->flag
& OPP_STRING
) {
185 __put_user('\'', buf
);
190 if (k
+ count
>= i
- 2)
196 copy_to_user(buf
+ k
- filp
->f_pos
,
197 op
->value
+ k
- 1, j
);
203 __put_user('\'', &buf
[k
++ - filp
->f_pos
]);
205 __put_user('\n', &buf
[k
++ - filp
->f_pos
]);
207 } else if (op
->flag
& OPP_STRINGLIST
) {
210 tmp
= kmalloc (i
, GFP_KERNEL
);
216 for (p
= op
->value
; p
< op
->value
+ op
->len
; p
++) {
226 copy_to_user(buf
, tmp
+ k
, count
);
231 } else if (op
->flag
& OPP_BINARY
) {
234 int first_off
, last_cnt
;
236 first
= ((u32
*)op
->value
) + k
/ 9;
238 last
= ((u32
*)op
->value
) + (k
+ count
- 1) / 9;
239 last_cnt
= (k
+ count
) % 9;
240 if (!last_cnt
) last_cnt
= 9;
243 sprintf (buffer
, "%08x.", *first
);
244 copy_to_user (buf
, buffer
+ first_off
, last_cnt
- first_off
);
245 buf
+= last_cnt
- first_off
;
247 for (q
= first
; q
<= last
; q
++) {
248 sprintf (buffer
, "%08x.", *q
);
250 copy_to_user (buf
, buffer
+ first_off
,
252 buf
+= 9 - first_off
;
253 } else if (q
== last
) {
254 copy_to_user (buf
, buffer
, last_cnt
);
257 copy_to_user (buf
, buffer
, 9);
263 if (last
== (u32
*)(op
->value
+ op
->len
- 4) && last_cnt
== 9)
264 __put_user('\n', (buf
- 1));
268 } else if (op
->flag
& OPP_HEXSTRING
) {
271 if ((k
< i
- 1) && (k
& 1)) {
272 sprintf (buffer
, "%02x", *(op
->value
+ (k
>> 1)));
273 __put_user(buffer
[1], &buf
[k
++ - filp
->f_pos
]);
277 for (; (count
> 1) && (k
< i
- 1); k
+= 2) {
278 sprintf (buffer
, "%02x", *(op
->value
+ (k
>> 1)));
279 copy_to_user (buf
+ k
- filp
->f_pos
, buffer
, 2);
283 if (count
&& (k
< i
- 1)) {
284 sprintf (buffer
, "%02x", *(op
->value
+ (k
>> 1)));
285 __put_user(buffer
[0], &buf
[k
++ - filp
->f_pos
]);
290 __put_user('\n', &buf
[k
++ - filp
->f_pos
]);
292 count
= k
- filp
->f_pos
;
297 static ssize_t
property_write(struct file
*filp
, const char *buf
,
298 size_t count
, loff_t
*ppos
)
304 openprom_property
*op
;
306 if (filp
->f_pos
>= 0xffffff)
308 if (!filp
->private_data
) {
309 i
= property_read (filp
, NULL
, 0, 0);
314 op
= (openprom_property
*)filp
->private_data
;
315 if (!(op
->flag
& OPP_STRING
)) {
317 int first_off
, last_cnt
;
323 for (i
= 0; i
< count
; i
++, j
++) {
327 __get_user(ctmp
, &buf
[i
]);
330 if (op
->flag
& OPP_BINARY
)
333 goto write_try_string
;
342 __get_user(ctmp
, &buf
[i
]);
344 (ctmp
> '9' && ctmp
< 'A') ||
345 (ctmp
> 'F' && ctmp
< 'a') ||
347 if (op
->flag
& OPP_BINARY
)
350 goto write_try_string
;
354 op
->flag
|= OPP_BINARY
;
356 i
= ((count
+ k
+ 8) / 9) << 2;
357 if (op
->alloclen
<= i
) {
358 b
= kmalloc (sizeof (openprom_property
) + 2 * i
,
362 memcpy (b
, filp
->private_data
,
363 sizeof (openprom_property
)
364 + strlen (op
->name
) + op
->alloclen
);
365 memset (((char *)b
) + sizeof (openprom_property
)
366 + strlen (op
->name
) + op
->alloclen
,
367 0, 2 * i
- op
->alloclen
);
368 op
= (openprom_property
*)b
;
370 b
= filp
->private_data
;
371 filp
->private_data
= (void *)op
;
374 first
= ((u32
*)op
->value
) + (k
/ 9);
376 last
= (u32
*)(op
->value
+ i
);
377 last_cnt
= (k
+ count
) % 9;
378 if (first
+ 1 == last
) {
379 memset (tmp
, '0', 8);
380 copy_from_user (tmp
+ first_off
, buf
,
381 (count
+ first_off
> 8) ? 8 - first_off
: count
);
384 for (j
= 0; j
< first_off
; j
++)
386 for (j
= 8 - count
- first_off
; j
> 0; j
--)
391 *first
|= simple_strtoul (tmp
, 0, 16);
392 op
->flag
|= OPP_DIRTY
;
395 op
->flag
|= OPP_DIRTY
;
396 for (q
= first
; q
< last
; q
++) {
399 memset (tmp
, '0', 8);
400 copy_from_user (tmp
+ first_off
, buf
,
403 for (j
= 0; j
< first_off
; j
++)
406 *q
|= simple_strtoul (tmp
,0,16);
409 } else if ((q
== last
- 1) && last_cnt
411 memset (tmp
, '0', 8);
412 copy_from_user (tmp
, buf
, last_cnt
);
414 for (j
= 0; j
< 8 - last_cnt
; j
++)
417 *q
|= simple_strtoul (tmp
, 0, 16);
420 char tchars
[17]; /* XXX yuck... */
422 copy_from_user(tchars
, buf
, 16);
423 *q
= simple_strtoul (tchars
, 0, 16);
433 filp
->f_pos
+= count
;
436 if (!(op
->flag
& OPP_BINARY
)) {
437 if (!(op
->flag
& (OPP_QUOTED
| OPP_NOTQUOTED
))) {
440 /* No way, if somebody starts writing from the middle,
441 * we don't know whether he uses quotes around or not
445 __get_user(ctmp
, buf
);
447 op
->flag
|= OPP_QUOTED
;
452 op
->flag
|= OPP_STRING
;
456 op
->flag
|= OPP_NOTQUOTED
;
458 op
->flag
|= OPP_STRING
;
459 if (op
->alloclen
<= count
+ filp
->f_pos
) {
460 b
= kmalloc (sizeof (openprom_property
)
461 + 2 * (count
+ filp
->f_pos
), GFP_KERNEL
);
464 memcpy (b
, filp
->private_data
,
465 sizeof (openprom_property
)
466 + strlen (op
->name
) + op
->alloclen
);
467 memset (((char *)b
) + sizeof (openprom_property
)
468 + strlen (op
->name
) + op
->alloclen
,
469 0, 2*(count
- filp
->f_pos
) - op
->alloclen
);
470 op
= (openprom_property
*)b
;
471 op
->alloclen
= 2*(count
+ filp
->f_pos
);
472 b
= filp
->private_data
;
473 filp
->private_data
= (void *)op
;
476 p
= op
->value
+ filp
->f_pos
- ((op
->flag
& OPP_QUOTED
) ? 1 : 0);
477 copy_from_user (p
, buf
, count
);
478 op
->flag
|= OPP_DIRTY
;
479 for (i
= 0; i
< count
; i
++, p
++)
485 op
->len
= p
- op
->value
;
486 filp
->f_pos
+= i
+ 1;
487 if ((p
> op
->value
) && (op
->flag
& OPP_QUOTED
)
488 && (*(p
- 1) == '\''))
491 if (p
- op
->value
> op
->len
)
492 op
->len
= p
- op
->value
;
493 filp
->f_pos
+= count
;
496 return filp
->f_pos
- k
;
499 int property_release (struct inode
*inode
, struct file
*filp
)
501 openprom_property
*op
= (openprom_property
*)filp
->private_data
;
508 node
= nodes
[(u16
)((long)inode
->u
.generic_ip
)].node
;
509 if ((u16
)((long)inode
->u
.generic_ip
) == aliases
) {
510 if ((op
->flag
& OPP_DIRTY
) && (op
->flag
& OPP_STRING
)) {
512 int i
= (op
->value
- op
->name
) - strlen (op
->name
) - 1;
513 op
->value
[op
->len
] = 0;
514 *(op
->value
- 1) = ' ';
516 for (p
= op
->value
- i
- 2; p
>= op
->name
; p
--)
520 memcpy (p
- 8, "nvalias ", 8);
523 } else if (op
->flag
& OPP_DIRTY
) {
524 if (op
->flag
& OPP_STRING
) {
525 op
->value
[op
->len
] = 0;
526 save_and_cli (flags
);
527 error
= prom_setprop (node
, op
->name
,
528 op
->value
, op
->len
+ 1);
529 restore_flags (flags
);
531 printk (KERN_WARNING
"/proc/openprom: "
532 "Couldn't write property %s\n",
534 } else if ((op
->flag
& OPP_BINARY
) || !op
->len
) {
535 save_and_cli (flags
);
536 error
= prom_setprop (node
, op
->name
,
538 restore_flags (flags
);
540 printk (KERN_WARNING
"/proc/openprom: "
541 "Couldn't write property %s\n",
544 printk (KERN_WARNING
"/proc/openprom: "
545 "Unknown property type of %s\n",
549 kfree (filp
->private_data
);
553 static struct file_operations openpromfs_prop_ops
= {
554 NULL
, /* lseek - default */
555 property_read
, /* read */
556 property_write
, /* write - bad */
558 NULL
, /* poll - default */
559 NULL
, /* ioctl - default */
561 NULL
, /* no special open code */
563 property_release
, /* no special release code */
564 NULL
/* can't fsync */
567 static struct inode_operations openpromfs_prop_inode_ops
= {
568 &openpromfs_prop_ops
, /* default property file-ops */
579 NULL
, /* follow_link */
580 NULL
, /* get_block */
582 NULL
, /* writepage */
583 NULL
, /* flushpage */
585 NULL
, /* permission */
587 NULL
/* revalidate */
590 static struct file_operations openpromfs_nodenum_ops
= {
591 NULL
, /* lseek - default */
592 nodenum_read
, /* read */
593 NULL
, /* write - bad */
595 NULL
, /* poll - default */
596 NULL
, /* ioctl - default */
598 NULL
, /* no special open code */
600 NULL
, /* no special release code */
601 NULL
/* can't fsync */
604 static struct inode_operations openpromfs_nodenum_inode_ops
= {
605 &openpromfs_nodenum_ops
,/* default .node file-ops */
616 NULL
, /* follow_link */
617 NULL
, /* get_block */
619 NULL
, /* writepage */
620 NULL
, /* flushpage */
622 NULL
, /* permission */
624 NULL
/* revalidate */
627 static struct file_operations openprom_alias_operations
= {
628 NULL
, /* lseek - default */
629 NULL
, /* read - bad */
630 NULL
, /* write - bad */
631 openpromfs_readdir
, /* readdir */
632 NULL
, /* poll - default */
633 NULL
, /* ioctl - default */
635 NULL
, /* no special open code */
637 NULL
, /* no special release code */
638 NULL
/* can't fsync */
641 static struct inode_operations openprom_alias_inode_operations
= {
642 &openprom_alias_operations
,/* default aliases directory file-ops */
643 openpromfs_create
, /* create */
644 openpromfs_lookup
, /* lookup */
646 openpromfs_unlink
, /* unlink */
653 NULL
, /* follow_link */
654 NULL
, /* get_block */
656 NULL
, /* writepage */
657 NULL
, /* flushpage */
659 NULL
, /* permission */
661 NULL
/* revalidate */
664 static int lookup_children(u16 n
, const char * name
, int len
)
668 for (; n
!= 0xffff; n
= nodes
[n
].next
) {
669 node
= nodes
[n
].child
;
670 if (node
!= 0xffff) {
675 while (node
!= 0xffff) {
676 if (prom_getname (nodes
[node
].node
,
680 && !strncmp (buffer
, name
, len
))
681 return NODE2INO(node
);
682 p
= strchr (buffer
, '@');
683 if (p
&& (len
== p
- buffer
)
684 && !strncmp (buffer
, name
, len
))
685 return NODE2INO(node
);
687 node
= nodes
[node
].next
;
691 ret
= lookup_children (nodes
[n
].child
, name
, len
);
697 static struct dentry
*openpromfs_lookup(struct inode
* dir
, struct dentry
*dentry
)
701 #define OPFSL_PROPERTY 1
702 #define OPFSL_NODENUM 2
703 #define OPFSL_DEVICE 3
713 struct openpromfs_dev
*d
= NULL
;
717 name
= dentry
->d_name
.name
;
718 len
= dentry
->d_name
.len
;
719 if (name
[0] == '.' && len
== 5 && !strncmp (name
+ 1, "node", 4)) {
720 ino
= NODEP2INO(NODE(dir
->i_ino
).first_prop
);
721 type
= OPFSL_NODENUM
;
724 u16 node
= NODE(dir
->i_ino
).child
;
725 while (node
!= 0xffff) {
726 if (prom_getname (nodes
[node
].node
, buffer
, 128) >= 0) {
728 if (len
== i
&& !strncmp (buffer
, name
, len
)) {
729 ino
= NODE2INO(node
);
733 p
= strchr (buffer
, '@');
734 if (p
&& (len
== p
- buffer
)
735 && !strncmp (buffer
, name
, len
)) {
736 ino
= NODE2INO(node
);
741 node
= nodes
[node
].next
;
744 n
= NODE(dir
->i_ino
).node
;
745 dirnode
= dir
->i_ino
- PROC_OPENPROM_FIRST
;
747 int j
= NODEP2INO(NODE(dir
->i_ino
).first_prop
);
748 if (dirnode
!= aliases
) {
749 for (p
= prom_firstprop (n
, buffer2
);
751 p
= prom_nextprop (n
, p
, buffer2
)) {
753 if ((len
== strlen (p
))
754 && !strncmp (p
, name
, len
)) {
756 type
= OPFSL_PROPERTY
;
762 for (k
= 0; k
< aliases_nodes
; k
++) {
765 && (len
== strlen (alias_names
[k
]))
766 && !strncmp (alias_names
[k
], name
, len
)) {
768 type
= OPFSL_PROPERTY
;
775 for (d
= *devices
; d
; d
= d
->next
)
776 if ((d
->node
== n
) && (strlen (d
->name
) == len
)
777 && !strncmp (d
->name
, name
, len
)) {
784 ino
= lookup_children (NODE(dir
->i_ino
).child
, name
, len
);
788 return ERR_PTR(-ENOENT
);
790 inode
= proc_get_inode (dir
->i_sb
, ino
, 0);
792 return ERR_PTR(-EINVAL
);
795 inode
->i_mode
= S_IFDIR
| S_IRUGO
| S_IXUGO
;
796 if (ino
== PROC_OPENPROM_FIRST
+ aliases
) {
797 inode
->i_mode
|= S_IWUSR
;
798 inode
->i_op
= &openprom_alias_inode_operations
;
800 inode
->i_op
= proc_openprom_iops
;
804 inode
->i_mode
= S_IFREG
| S_IRUGO
;
805 inode
->i_op
= &openpromfs_nodenum_inode_ops
;
807 inode
->u
.generic_ip
= (void *)(long)(n
);
810 if ((dirnode
== options
) && (len
== 17)
811 && !strncmp (name
, "security-password", 17))
812 inode
->i_mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
814 inode
->i_mode
= S_IFREG
| S_IRUGO
;
815 if (dirnode
== options
|| dirnode
== aliases
) {
816 if (len
!= 4 || strncmp (name
, "name", 4))
817 inode
->i_mode
|= S_IWUSR
;
820 inode
->i_op
= &openpromfs_prop_inode_ops
;
822 if (inode
->i_size
< 0)
824 inode
->u
.generic_ip
= (void *)(long)(((u16
)dirnode
) |
825 (((u16
)(ino
- NODEP2INO(NODE(dir
->i_ino
).first_prop
) - 1)) << 16));
828 inode
->i_mode
= d
->mode
;
829 inode
->i_op
= &chrdev_inode_operations
;
831 inode
->i_rdev
= d
->rdev
;
838 d_add(dentry
, inode
);
842 static int openpromfs_readdir(struct file
* filp
, void * dirent
, filldir_t filldir
)
844 struct inode
*inode
= filp
->f_dentry
->d_inode
;
851 struct openpromfs_dev
*d
;
858 if (filldir(dirent
, ".", 1, i
, ino
) < 0) return 0;
863 if (filldir(dirent
, "..", 2, i
,
864 (NODE(ino
).parent
== 0xffff) ?
865 PROC_ROOT_INO
: NODE2INO(NODE(ino
).parent
)) < 0)
872 node
= NODE(ino
).child
;
873 while (i
&& node
!= 0xffff) {
874 node
= nodes
[node
].next
;
877 while (node
!= 0xffff) {
878 if (prom_getname (nodes
[node
].node
, buffer
, 128) < 0)
880 if (filldir(dirent
, buffer
, strlen(buffer
),
881 filp
->f_pos
, NODE2INO(node
)) < 0)
884 node
= nodes
[node
].next
;
886 j
= NODEP2INO(NODE(ino
).first_prop
);
888 if (filldir(dirent
, ".node", 5, filp
->f_pos
, j
) < 0)
894 if (ino
== PROC_OPENPROM_FIRST
+ aliases
) {
895 for (j
++; i
< aliases_nodes
; i
++, j
++) {
896 if (alias_names
[i
]) {
897 if (filldir (dirent
, alias_names
[i
],
898 strlen (alias_names
[i
]),
899 filp
->f_pos
, j
) < 0) return 0;
904 for (p
= prom_firstprop (n
, buffer2
);
906 p
= prom_nextprop (n
, p
, buffer2
)) {
910 if (filldir(dirent
, p
, strlen(p
),
917 for (d
= *devices
; d
; d
= d
->next
) {
921 if (filldir(dirent
, d
->name
,
923 filp
->f_pos
, d
->inode
) < 0)
933 static int openpromfs_create (struct inode
*dir
, struct dentry
*dentry
, int mode
)
940 if (dentry
->d_name
.len
> 256)
942 if (aliases_nodes
== ALIASES_NNODES
)
944 p
= kmalloc (dentry
->d_name
.len
+ 1, GFP_KERNEL
);
947 strncpy (p
, dentry
->d_name
.name
, dentry
->d_name
.len
);
948 p
[dentry
->d_name
.len
] = 0;
949 alias_names
[aliases_nodes
++] = p
;
950 inode
= proc_get_inode (dir
->i_sb
,
951 NODEP2INO(NODE(dir
->i_ino
).first_prop
)
955 inode
->i_mode
= S_IFREG
| S_IRUGO
| S_IWUSR
;
956 inode
->i_op
= &openpromfs_prop_inode_ops
;
958 if (inode
->i_size
< 0) inode
->i_size
= 0;
959 inode
->u
.generic_ip
= (void *)(long)(((u16
)aliases
) |
960 (((u16
)(aliases_nodes
- 1)) << 16));
961 d_instantiate(dentry
, inode
);
965 static int openpromfs_unlink (struct inode
*dir
, struct dentry
*dentry
)
972 name
= dentry
->d_name
.name
;
973 len
= dentry
->d_name
.len
;
974 for (i
= 0; i
< aliases_nodes
; i
++)
975 if ((strlen (alias_names
[i
]) == len
)
976 && !strncmp (name
, alias_names
[i
], len
)) {
980 alias_names
[i
] = NULL
;
982 strcpy (buffer
, "nvunalias ");
983 memcpy (buffer
+ 10, name
, len
);
984 buffer
[10 + len
] = 0;
991 /* {{{ init section */
993 static int __init
check_space (u16 n
)
995 static int check_space (u16 n
)
1000 if ((1 << alloced
) * PAGE_SIZE
< (n
+ 2) * sizeof(openpromfs_node
)) {
1001 pages
= __get_free_pages (GFP_KERNEL
, alloced
+ 1);
1006 memcpy ((char *)pages
, (char *)nodes
,
1007 (1 << alloced
) * PAGE_SIZE
);
1008 free_pages ((unsigned long)nodes
, alloced
);
1011 nodes
= (openpromfs_node
*)pages
;
1017 static u16 __init
get_nodes (u16 parent
, u32 node
)
1019 static u16
get_nodes (u16 parent
, u32 node
)
1023 u16 n
= last_node
++, i
;
1026 if (check_space (n
) < 0)
1028 nodes
[n
].parent
= parent
;
1029 nodes
[n
].node
= node
;
1030 nodes
[n
].next
= 0xffff;
1031 nodes
[n
].child
= 0xffff;
1032 nodes
[n
].first_prop
= first_prop
++;
1037 if ((j
= prom_getproperty (node
, "name", buffer
, 8)) >= 0) {
1039 if (!strcmp (buffer
, "options"))
1041 else if (!strcmp (buffer
, "aliases"))
1046 for (p
= prom_firstprop (node
, buffer
);
1047 p
&& p
!= (char *)-1 && *p
;
1048 p
= prom_nextprop (node
, p
, buffer
))
1052 for (p
= prom_firstprop (node
, buffer
);
1053 p
&& p
!= (char *)-1 && *p
;
1054 p
= prom_nextprop (node
, p
, buffer
)) {
1055 if (aliases_nodes
== ALIASES_NNODES
)
1057 for (i
= 0; i
< aliases_nodes
; i
++)
1058 if (!strcmp (p
, alias_names
[i
]))
1060 if (i
< aliases_nodes
)
1062 q
= kmalloc (strlen (p
) + 1, GFP_KERNEL
);
1066 alias_names
[aliases_nodes
++] = q
;
1068 first_prop
+= ALIASES_NNODES
;
1070 node
= prom_getchild (node
);
1072 parent
= get_nodes (n
, node
);
1073 if (parent
== 0xffff)
1075 nodes
[n
].child
= parent
;
1076 while ((node
= prom_getsibling (node
)) != 0) {
1077 i
= get_nodes (n
, node
);
1080 nodes
[parent
].next
= i
;
1089 void openpromfs_use (struct inode
*inode
, int inc
)
1091 static int root_fresh
= 1;
1092 static int dec_first
= 1;
1093 #ifdef OPENPROM_DEBUGGING
1094 static int usec
= 0;
1097 if (inode
->i_count
== 1)
1099 else if (root_fresh
&& inode
->i_ino
== PROC_OPENPROM_FIRST
) {
1104 if (inode
->i_ino
== PROC_OPENPROM_FIRST
)
1109 printk ("openpromfs_use: %d %d %d %d\n",
1110 inode
->i_ino
, inc
, usec
, inode
->i_count
);
1113 if (inode
->i_count
== 1)
1115 else if (root_fresh
&& inode
->i_ino
== PROC_OPENPROM_FIRST
) {
1120 if (inode
->i_ino
== PROC_OPENPROM_FIRST
)
1130 #define openpromfs_use 0
1135 void __init
openpromfs_init (void)
1141 int init_module (void)
1144 nodes
= (openpromfs_node
*)__get_free_pages(GFP_KERNEL
, 0);
1146 printk (KERN_WARNING
"/proc/openprom: can't get free page\n");
1149 if (get_nodes (0xffff, prom_root_node
) == 0xffff) {
1150 printk (KERN_WARNING
"/proc/openprom: couldn't setup tree\n");
1153 nodes
[last_node
].first_prop
= first_prop
;
1154 proc_openprom_iops
= proc_openprom_register (openpromfs_readdir
,
1162 void cleanup_module (void)
1165 proc_openprom_deregister ();
1166 free_pages ((unsigned long)nodes
, alloced
);
1167 for (i
= 0; i
< aliases_nodes
; i
++)
1168 if (alias_names
[i
])
1169 kfree (alias_names
[i
]);