3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * hcl - SGI's Hardware Graph compatibility layer.
9 * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
12 #include <linux/types.h>
13 #include <linux/config.h>
14 #include <linux/slab.h>
15 #include <linux/ctype.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <asm/sn/sgi.h>
19 #include <linux/devfs_fs.h>
20 #include <linux/devfs_fs_kernel.h>
22 #include <asm/sn/iograph.h>
23 #include <asm/sn/invent.h>
24 #include <asm/sn/hcl.h>
25 #include <asm/sn/labelcl.h>
27 #define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER"
28 #define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE"
29 #define HCL_TEMP_NAME_LEN 44
30 #define HCL_VERSION "1.0"
31 devfs_handle_t hwgraph_root
= NULL
;
32 devfs_handle_t linux_busnum
= NULL
;
35 * Debug flag definition.
37 #define OPTION_NONE 0x00
38 #define HCL_DEBUG_NONE 0x00000
39 #define HCL_DEBUG_ALL 0x0ffff
40 #if defined(CONFIG_HCL_DEBUG)
41 static unsigned int hcl_debug_init __initdata
= HCL_DEBUG_NONE
;
43 static unsigned int hcl_debug
= HCL_DEBUG_NONE
;
44 #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
45 static unsigned int boot_options
= OPTION_NONE
;
49 * Some Global definitions.
51 devfs_handle_t hcl_handle
= NULL
;
53 invplace_t invplace_none
= {
55 GRAPH_VERTEX_PLACE_NONE
,
61 * The purpose of this device driver is to provide a facility
62 * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path
63 * to manipulate label entries without having to implement
64 * system call interfaces. This methodology will enable us to
65 * make this feature module loadable.
67 static int hcl_open(struct inode
* inode
, struct file
* filp
)
70 printk("HCL: hcl_open called.\n");
77 static int hcl_close(struct inode
* inode
, struct file
* filp
)
81 printk("HCL: hcl_close called.\n");
88 static int hcl_ioctl(struct inode
* inode
, struct file
* file
,
89 unsigned int cmd
, unsigned long arg
)
93 printk("HCL: hcl_ioctl called.\n");
99 printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd
);
107 struct file_operations hcl_fops
= {
109 NULL
, /* lseek - default */
110 NULL
, /* read - general block-dev read */
111 NULL
, /* write - general block-dev write */
112 NULL
, /* readdir - bad */
114 hcl_ioctl
, /* ioctl */
118 hcl_close
, /* release */
128 * init_hcl() - Boot time initialization. Ensure that it is called
129 * after devfs has been initialized.
131 * For now this routine is being called out of devfs/base.c. Actually
132 * Not a bad place to be ..
136 int init_module (void)
138 int __init
init_hcl(void)
141 extern void string_table_init(struct string_table
*);
142 extern struct string_table label_string_table
;
143 extern int init_ifconfig_net(void);
146 #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
147 printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n",
148 HCL_NAME
, HCL_VERSION
);
150 hcl_debug
= hcl_debug_init
;
151 printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME
, hcl_debug
);
152 printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME
, boot_options
);
156 * Create the hwgraph_root on devfs.
158 rv
= hwgraph_path_add(NULL
, EDGE_LBL_HW
, &hwgraph_root
);
160 printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv
);
163 * Create the hcl driver to support inventory entry manipulations.
164 * By default, it is expected that devfs is mounted on /dev.
167 hcl_handle
= hwgraph_register(hwgraph_root
, ".hcl",
168 0, DEVFS_FL_AUTO_DEVNUM
,
170 S_IFCHR
| S_IRUSR
| S_IWUSR
| S_IRGRP
, 0, 0,
173 if (hcl_handle
== NULL
) {
174 panic("HCL: Unable to create HCL Driver in init_hcl().\n");
179 * Initialize the HCL string table.
181 string_table_init(&label_string_table
);
184 * Create the directory that links Linux bus numbers to our Xwidget.
186 rv
= hwgraph_path_add(hwgraph_root
, EDGE_LBL_LINUX_BUS
, &linux_busnum
);
187 if (linux_busnum
== NULL
) {
188 panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS
);
193 * Initialize the ifconfgi_net driver that does network devices
204 * hcl_setup() - Process boot time parameters if given.
206 * This routine gets called only if "hcl=" is given in the
207 * boot line and before init_hcl().
209 * We currently do not have any boot options .. when we do,
210 * functionalities can be added here.
213 static int __init
hcl_setup(char *str
)
215 while ( (*str
!= '\0') && !isspace (*str
) )
217 #ifdef CONFIG_HCL_DEBUG
218 if (strncmp (str
, "all", 3) == 0) {
219 hcl_debug_init
|= HCL_DEBUG_ALL
;
224 if (*str
!= ',') return 0;
232 __setup("hcl=", hcl_setup
);
236 * Set device specific "fast information".
240 hwgraph_fastinfo_set(devfs_handle_t de
, arbitrary_info_t fastinfo
)
244 printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ld\n", (void *)de
, fastinfo
);
247 labelcl_info_replace_IDX(de
, HWGRAPH_FASTINFO
, fastinfo
, NULL
);
253 * Get device specific "fast information".
257 hwgraph_fastinfo_get(devfs_handle_t de
)
259 arbitrary_info_t fastinfo
;
263 printk(KERN_WARNING
"HCL: hwgraph_fastinfo_get handle given is NULL.\n");
267 rv
= labelcl_info_get_IDX(de
, HWGRAPH_FASTINFO
, &fastinfo
);
276 * hwgraph_connectpt_set - Sets the connect point handle in de to the
277 * given connect_de handle. By default, the connect point of the
278 * devfs node is the parent. This effectively changes this assumption.
281 hwgraph_connectpt_set(devfs_handle_t de
, devfs_handle_t connect_de
)
288 rv
= labelcl_info_connectpt_set(de
, connect_de
);
295 * hwgraph_connectpt_get: Returns the entry's connect point in the devfs
299 hwgraph_connectpt_get(devfs_handle_t de
)
302 arbitrary_info_t info
;
303 devfs_handle_t connect
;
305 rv
= labelcl_info_get_IDX(de
, HWGRAPH_CONNECTPT
, &info
);
310 connect
= (devfs_handle_t
)info
;
317 * hwgraph_mk_dir - Creates a directory entry with devfs.
318 * Note that a directory entry in devfs can have children
319 * but it cannot be a char|block special file.
322 hwgraph_mk_dir(devfs_handle_t de
, const char *name
,
323 unsigned int namelen
, void *info
)
327 labelcl_info_t
*labelcl_info
= NULL
;
328 devfs_handle_t new_devfs_handle
= NULL
;
329 devfs_handle_t parent
= NULL
;
332 * Create the device info structure for hwgraph compatiblity support.
334 labelcl_info
= labelcl_info_create();
339 * Create a devfs entry.
341 new_devfs_handle
= devfs_mk_dir(de
, name
, (void *)labelcl_info
);
342 if (!new_devfs_handle
) {
343 labelcl_info_destroy(labelcl_info
);
348 * Get the parent handle.
350 parent
= devfs_get_parent (new_devfs_handle
);
353 * To provide the same semantics as the hwgraph, set the connect point.
355 rv
= hwgraph_connectpt_set(new_devfs_handle
, parent
);
358 * We need to clean up!
363 * If the caller provides a private data pointer, save it in the
364 * labelcl info structure(fastinfo). This can be retrieved via
365 * hwgraph_fastinfo_get()
368 hwgraph_fastinfo_set(new_devfs_handle
, (arbitrary_info_t
)info
);
370 return(new_devfs_handle
);
375 * hwgraph_vertex_create - Create a vertex by giving it a temp name.
379 * hwgraph_path_add - Create a directory node with the given path starting
380 * from the given devfs_handle_t.
382 extern char * dev_to_name(devfs_handle_t
, char *, uint
);
384 hwgraph_path_add(devfs_handle_t fromv
,
386 devfs_handle_t
*new_de
)
389 unsigned int namelen
= strlen(path
);
393 * We need to handle the case when fromv is NULL ..
394 * in this case we need to create the path from the
398 fromv
= hwgraph_root
;
401 * check the entry doesn't already exist, if it does
402 * then we simply want new_de to point to it (otherwise
403 * we'll overwrite the existing labelcl_info struct)
405 rv
= hwgraph_edge_get(fromv
, path
, new_de
);
406 if (rv
) { /* couldn't find entry so we create it */
407 *new_de
= hwgraph_mk_dir(fromv
, path
, namelen
, NULL
);
419 * hwgraph_register - Creates a file entry with devfs.
420 * Note that a file entry cannot have children .. it is like a
421 * char|block special vertex in hwgraph.
424 hwgraph_register(devfs_handle_t de
, const char *name
,
425 unsigned int namelen
, unsigned int flags
,
426 unsigned int major
, unsigned int minor
,
427 umode_t mode
, uid_t uid
, gid_t gid
,
428 struct file_operations
*fops
,
433 void *labelcl_info
= NULL
;
434 devfs_handle_t new_devfs_handle
= NULL
;
435 devfs_handle_t parent
= NULL
;
438 * Create the labelcl info structure for hwgraph compatiblity support.
440 labelcl_info
= labelcl_info_create();
445 * Create a devfs entry.
447 new_devfs_handle
= devfs_register(de
, name
, flags
, major
,
448 minor
, mode
, fops
, labelcl_info
);
449 if (!new_devfs_handle
) {
450 labelcl_info_destroy((labelcl_info_t
*)labelcl_info
);
455 * Get the parent handle.
458 parent
= devfs_get_parent (new_devfs_handle
);
463 * To provide the same semantics as the hwgraph, set the connect point.
465 rv
= hwgraph_connectpt_set(new_devfs_handle
, parent
);
468 * We need to clean up!
470 printk(KERN_WARNING
"HCL: Unable to set the connect point to its parent 0x%p\n",
471 (void *)new_devfs_handle
);
475 * If the caller provides a private data pointer, save it in the
476 * labelcl info structure(fastinfo). This can be retrieved via
477 * hwgraph_fastinfo_get()
480 hwgraph_fastinfo_set(new_devfs_handle
, (arbitrary_info_t
)info
);
482 return(new_devfs_handle
);
488 * hwgraph_mk_symlink - Create a symbolic link.
491 hwgraph_mk_symlink(devfs_handle_t de
, const char *name
, unsigned int namelen
,
492 unsigned int flags
, const char *link
, unsigned int linklen
,
493 devfs_handle_t
*handle
, void *info
)
496 void *labelcl_info
= NULL
;
498 devfs_handle_t new_devfs_handle
= NULL
;
501 * Create the labelcl info structure for hwgraph compatiblity support.
503 labelcl_info
= labelcl_info_create();
508 * Create a symbolic link devfs entry.
510 status
= devfs_mk_symlink(de
, name
, flags
, link
,
511 &new_devfs_handle
, labelcl_info
);
512 if ( (!new_devfs_handle
) || (!status
) ){
513 labelcl_info_destroy((labelcl_info_t
*)labelcl_info
);
518 * If the caller provides a private data pointer, save it in the
519 * labelcl info structure(fastinfo). This can be retrieved via
520 * hwgraph_fastinfo_get()
523 hwgraph_fastinfo_set(new_devfs_handle
, (arbitrary_info_t
)info
);
525 *handle
= new_devfs_handle
;
531 * hwgraph_vertex_get_next - this routine returns the next sibbling for the
532 * device entry given in de. If there are no more sibbling, NULL
533 * is returned in next_sibbling.
535 * Currently we do not have any protection against de being deleted
536 * while it's handle is being held.
539 hwgraph_vertex_get_next(devfs_handle_t
*next_sibbling
, devfs_handle_t
*de
)
541 *next_sibbling
= devfs_get_next_sibling (*de
);
543 if (*next_sibbling
!= NULL
)
544 *de
= *next_sibbling
;
550 * hwgraph_vertex_destroy - Destroy the devfs entry
553 hwgraph_vertex_destroy(devfs_handle_t de
)
556 void *labelcl_info
= NULL
;
558 labelcl_info
= devfs_get_info(de
);
559 devfs_unregister(de
);
562 labelcl_info_destroy((labelcl_info_t
*)labelcl_info
);
568 ** See if a vertex has an outgoing edge with a specified name.
569 ** Vertices in the hwgraph *implicitly* contain these edges:
570 ** "." refers to "current vertex"
571 ** ".." refers to "connect point vertex"
572 ** "char" refers to current vertex (character device access)
573 ** "block" refers to current vertex (block device access)
577 * hwgraph_edge_add - This routines has changed from the original conext.
578 * All it does now is to create a symbolic link from "from" to "to".
582 hwgraph_edge_add(devfs_handle_t from
, devfs_handle_t to
, char *name
)
589 devfs_handle_t handle
= NULL
;
593 path
= kmalloc(1024, GFP_KERNEL
);
594 memset(path
, 0x0, 1024);
595 name_start
= devfs_generate_path (from
, path
, 1024);
596 s1
= &path
[name_start
];
599 index
= strstr (s1
, "/");
609 memset(path
, 0x0, 1024);
610 name_start
= devfs_generate_path (to
, path
, 1024);
612 for (i
= 0; i
< count
; i
++) {
616 strcat(path
, &path
[name_start
]);
619 * Otherwise, just create a symlink to the vertex.
620 * In this case the vertex was previous created with a REAL pathname.
622 rv
= devfs_mk_symlink (from
, (const char *)name
,
623 DEVFS_FL_DEFAULT
, path
,
626 name_start
= devfs_generate_path (handle
, path
, 1024);
633 hwgraph_edge_get(devfs_handle_t from
, char *name
, devfs_handle_t
*toptr
)
637 devfs_handle_t target_handle
= NULL
;
646 * If the name is "." just return the current devfs entry handle.
648 if (!strcmp(name
, HWGRAPH_EDGELBL_DOT
)) {
652 } else if (!strcmp(name
, HWGRAPH_EDGELBL_DOTDOT
)) {
654 * Hmmm .. should we return the connect point or parent ..
655 * see in hwgraph, the concept of parent is the connectpt!
657 * Maybe we should see whether the connectpt is set .. if
658 * not just return the parent!
660 target_handle
= hwgraph_connectpt_get(from
);
663 * Just return the connect point.
665 *toptr
= target_handle
;
668 target_handle
= devfs_get_parent(from
);
669 *toptr
= target_handle
;
673 * Call devfs to get the devfs entry.
675 namelen
= (int) strlen(name
);
676 target_handle
= devfs_get_handle(from
, name
, 1); /* Yes traverse symbolic links */
677 if (target_handle
== NULL
)
680 *toptr
= target_handle
;
688 * hwgraph_edge_get_next - Retrieves the next sibbling given the current
689 * entry number "placeptr".
691 * Allow the caller to retrieve walk through the sibblings of "source"
692 * devfs_handle_t. The implicit edges "." and ".." is returned first
693 * followed by each of the real children.
695 * We may end up returning garbage if another thread perform any deletion
696 * in this directory before "placeptr".
701 hwgraph_edge_get_next(devfs_handle_t source
, char *name
, devfs_handle_t
*target
,
707 unsigned int namelen
= 0;
708 const char *tempname
= NULL
;
710 if (placeptr
== NULL
)
713 which_place
= *placeptr
;
716 if (which_place
<= HWGRAPH_RESERVED_PLACES
) {
717 if (which_place
== EDGE_PLACE_WANT_CURRENT
) {
720 * Return the current devfs handle.
723 strcpy(name
, HWGRAPH_EDGELBL_DOT
);
725 if (target
!= NULL
) {
727 /* XXX should incr "source" ref count here if we
728 * ever implement ref counts */
731 } else if (which_place
== EDGE_PLACE_WANT_CONNECTPT
) {
733 * Looking for the connect point or parent.
734 * If the connect point is set .. it returns the connect point.
735 * Otherwise, it returns the parent .. will we support
738 devfs_handle_t connect_point
= hwgraph_connectpt_get(source
);
740 if (connect_point
== NULL
) {
742 * No connectpoint set .. either the User
743 * explicitly NULL it or this node was not
751 strcpy(name
, HWGRAPH_EDGELBL_DOTDOT
);
754 *target
= connect_point
;
756 } else if (which_place
== EDGE_PLACE_WANT_REAL_EDGES
) {
758 * return first "real" entry in directory, and increment
759 * placeptr. Next time around we should have
760 * which_place > HWGRAPH_RESERVED_EDGES so we'll fall through
761 * this nested if block.
763 *target
= devfs_get_first_child(source
);
764 if (*target
&& name
) {
765 tempname
= devfs_get_name(*target
, &namelen
);
766 if (tempname
&& namelen
)
767 strcpy(name
, tempname
);
770 *placeptr
= which_place
+ 1;
774 *placeptr
= which_place
+1;
779 * walk linked list, (which_place - HWGRAPH_RESERVED_PLACES) times
785 for (curr
=devfs_get_first_child(source
), i
= i
+HWGRAPH_RESERVED_PLACES
;
786 curr
!=NULL
&& i
<which_place
;
787 curr
=devfs_get_next_sibling(curr
), i
++)
790 *placeptr
= which_place
+ 1;
792 tempname
= devfs_get_name(*target
, &namelen
);
793 if (tempname
&& namelen
)
794 strcpy(name
, tempname
);
804 * hwgraph_info_add_LBL - Adds a new label for the device. Mark the info_desc
805 * of the label as INFO_DESC_PRIVATE and store the info in the label.
809 hwgraph_info_add_LBL( devfs_handle_t de
,
811 arbitrary_info_t info
)
813 return(labelcl_info_add_LBL(de
, name
, INFO_DESC_PRIVATE
, info
));
817 * hwgraph_info_remove_LBL - Remove the label entry for the device.
821 hwgraph_info_remove_LBL( devfs_handle_t de
,
823 arbitrary_info_t
*old_info
)
825 return(labelcl_info_remove_LBL(de
, name
, NULL
, old_info
));
829 * hwgraph_info_replace_LBL - replaces an existing label with
830 * a new label info value.
834 hwgraph_info_replace_LBL( devfs_handle_t de
,
836 arbitrary_info_t info
,
837 arbitrary_info_t
*old_info
)
839 return(labelcl_info_replace_LBL(de
, name
,
840 INFO_DESC_PRIVATE
, info
,
844 * hwgraph_info_get_LBL - Get and return the info value in the label of the
849 hwgraph_info_get_LBL( devfs_handle_t de
,
851 arbitrary_info_t
*infop
)
853 return(labelcl_info_get_LBL(de
, name
, NULL
, infop
));
857 * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer
858 * of the given label for the device. The weird thing is that the label
859 * that matches the name is return irrespective of the info_desc value!
860 * Do not understand why the word "exported" is used!
864 hwgraph_info_get_exported_LBL( devfs_handle_t de
,
867 arbitrary_info_t
*infop
)
870 arb_info_desc_t info_desc
;
872 rc
= labelcl_info_get_LBL(de
, name
, &info_desc
, infop
);
874 *export_info
= (int)info_desc
;
880 * hwgraph_info_get_next_LBL - Returns the next label info given the
881 * current label entry in place.
883 * Once again this has no locking or reference count for protection.
888 hwgraph_info_get_next_LBL( devfs_handle_t de
,
890 arbitrary_info_t
*infop
,
891 labelcl_info_place_t
*place
)
893 return(labelcl_info_get_next_LBL(de
, buf
, NULL
, infop
, place
));
897 * hwgraph_info_export_LBL - Retrieve the specified label entry and modify
898 * the info_desc field with the given value in nbytes.
902 hwgraph_info_export_LBL(devfs_handle_t de
, char *name
, int nbytes
)
904 arbitrary_info_t info
;
908 nbytes
= INFO_DESC_EXPORT
;
913 rc
= labelcl_info_get_LBL(de
, name
, NULL
, &info
);
917 rc
= labelcl_info_replace_LBL(de
, name
,
918 nbytes
, info
, NULL
, NULL
);
924 * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the
925 * label info_descr filed to INFO_DESC_PRIVATE.
929 hwgraph_info_unexport_LBL(devfs_handle_t de
, char *name
)
931 arbitrary_info_t info
;
934 rc
= labelcl_info_get_LBL(de
, name
, NULL
, &info
);
938 rc
= labelcl_info_replace_LBL(de
, name
,
939 INFO_DESC_PRIVATE
, info
, NULL
, NULL
);
945 * hwgraph_path_lookup - return the handle for the given path.
949 hwgraph_path_lookup( devfs_handle_t start_vertex_handle
,
951 devfs_handle_t
*vertex_handle_ptr
,
954 *vertex_handle_ptr
= devfs_get_handle(start_vertex_handle
, /* start dir */
955 lookup_path
, /* path */
956 1); /* traverse symlinks */
957 if (*vertex_handle_ptr
== NULL
)
964 * hwgraph_traverse - Find and return the devfs handle starting from de.
968 hwgraph_traverse(devfs_handle_t de
, char *path
, devfs_handle_t
*found
)
971 * get the directory entry (path should end in a directory)
974 *found
= devfs_get_handle(de
, /* start dir */
976 1); /* traverse symlinks */
978 return(GRAPH_NOT_FOUND
);
980 return(GRAPH_SUCCESS
);
984 * hwgraph_path_to_vertex - Return the devfs entry handle for the given
985 * pathname .. assume traverse symlinks too!.
988 hwgraph_path_to_vertex(char *path
)
990 return(devfs_get_handle(NULL
, /* start dir */
992 1)); /* traverse symlinks */
996 * hwgraph_path_to_dev - Returns the devfs_handle_t of the given path ..
997 * We only deal with devfs handle and not devfs_handle_t.
1000 hwgraph_path_to_dev(char *path
)
1004 de
= hwgraph_path_to_vertex(path
);
1009 * hwgraph_block_device_get - return the handle of the block device file.
1010 * The assumption here is that de is a directory.
1013 hwgraph_block_device_get(devfs_handle_t de
)
1015 return(devfs_get_handle(de
, /* start dir */
1017 1)); /* traverse symlinks */
1021 * hwgraph_char_device_get - return the handle of the char device file.
1022 * The assumption here is that de is a directory.
1025 hwgraph_char_device_get(devfs_handle_t de
)
1027 return(devfs_get_handle(de
, /* start dir */
1029 1)); /* traverse symlinks */
1033 ** Inventory is now associated with a vertex in the graph. For items that
1034 ** belong in the inventory but have no vertex
1035 ** (e.g. old non-graph-aware drivers), we create a bogus vertex under the
1036 ** INFO_LBL_INVENT name.
1038 ** For historical reasons, we prevent exact duplicate entries from being added
1039 ** to a single vertex.
1043 * hwgraph_inventory_add - Adds an inventory entry into de.
1046 hwgraph_inventory_add( devfs_handle_t de
,
1053 inventory_t
*pinv
= NULL
, *old_pinv
= NULL
, *last_pinv
= NULL
;
1057 * Add our inventory data to the list of inventory data
1058 * associated with this vertex.
1061 /* GRAPH_LOCK_UPDATE(&invent_lock); */
1062 rv
= labelcl_info_get_LBL(de
,
1064 NULL
, (arbitrary_info_t
*)&old_pinv
);
1065 if ((rv
!= LABELCL_SUCCESS
) && (rv
!= LABELCL_NOT_FOUND
))
1069 * Seek to end of inventory items associated with this
1070 * vertex. Along the way, make sure we're not duplicating
1071 * an inventory item (for compatibility with old add_to_inventory)
1073 for (;old_pinv
; last_pinv
= old_pinv
, old_pinv
= old_pinv
->inv_next
) {
1074 if ((int)class != -1 && old_pinv
->inv_class
!= class)
1076 if ((int)type
!= -1 && old_pinv
->inv_type
!= type
)
1078 if ((int)state
!= -1 && old_pinv
->inv_state
!= state
)
1080 if ((int)controller
!= -1
1081 && old_pinv
->inv_controller
!= controller
)
1083 if ((int)unit
!= -1 && old_pinv
->inv_unit
!= unit
)
1086 /* exact duplicate of previously-added inventory item */
1091 /* Not a duplicate, so we know that we need to add something. */
1093 /* Release lock while we wait for memory. */
1094 /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
1095 pinv
= (inventory_t
*)kmalloc(sizeof(inventory_t
), GFP_KERNEL
);
1096 replace_in_inventory(pinv
, class, type
, controller
, unit
, state
);
1100 pinv
->inv_next
= NULL
;
1102 last_pinv
->inv_next
= pinv
;
1104 rv
= labelcl_info_add_LBL(de
, INFO_LBL_INVENT
,
1105 sizeof(inventory_t
), (arbitrary_info_t
)pinv
);
1111 /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
1115 /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
1123 * hwgraph_inventory_remove - Removes an inventory entry.
1125 * Remove an inventory item associated with a vertex. It is the caller's
1126 * responsibility to make sure that there are no races between removing
1127 * inventory from a vertex and simultaneously removing that vertex.
1130 hwgraph_inventory_remove( devfs_handle_t de
,
1137 inventory_t
*pinv
= NULL
, *last_pinv
= NULL
, *next_pinv
= NULL
;
1141 * We never remove stuff from ".invent" ..
1147 * Remove our inventory data to the list of inventory data
1148 * associated with this vertex.
1150 /* GRAPH_LOCK_UPDATE(&invent_lock); */
1151 rv
= labelcl_info_get_LBL(de
,
1153 NULL
, (arbitrary_info_t
*)&pinv
);
1154 if (rv
!= LABELCL_SUCCESS
)
1158 * Search through inventory items associated with this
1159 * vertex, looking for a match.
1161 for (;pinv
; pinv
= next_pinv
) {
1162 next_pinv
= pinv
->inv_next
;
1164 if(((int)class == -1 || pinv
->inv_class
== class) &&
1165 ((int)type
== -1 || pinv
->inv_type
== type
) &&
1166 ((int)state
== -1 || pinv
->inv_state
== state
) &&
1167 ((int)controller
== -1 || pinv
->inv_controller
== controller
) &&
1168 ((int)unit
== -1 || pinv
->inv_unit
== unit
)) {
1170 /* Found a matching inventory item. Remove it. */
1172 last_pinv
->inv_next
= pinv
->inv_next
;
1174 rv
= hwgraph_info_replace_LBL(de
, INFO_LBL_INVENT
, (arbitrary_info_t
)pinv
->inv_next
, NULL
);
1175 if (rv
!= LABELCL_SUCCESS
)
1179 pinv
->inv_next
= NULL
; /* sanity */
1185 if (last_pinv
== NULL
) {
1186 rv
= hwgraph_info_remove_LBL(de
, INFO_LBL_INVENT
, NULL
);
1187 if (rv
!= LABELCL_SUCCESS
)
1191 rv
= LABELCL_SUCCESS
;
1194 /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
1199 * hwgraph_inventory_get_next - Get next inventory item associated with the
1202 * No locking is really needed. We don't yet have the ability
1203 * to remove inventory items, and new items are always added to
1204 * the end of a vertex' inventory list.
1206 * However, a devfs entry can be removed!
1209 hwgraph_inventory_get_next(devfs_handle_t de
, invplace_t
*place
, inventory_t
**ppinv
)
1215 return(LABELCL_BAD_PARAM
);
1217 if (place
->invplace_vhdl
== NULL
) {
1218 place
->invplace_vhdl
= de
;
1219 place
->invplace_inv
= NULL
;
1222 if (de
!= place
->invplace_vhdl
)
1223 return(LABELCL_BAD_PARAM
);
1225 if (place
->invplace_inv
== NULL
) {
1226 /* Just starting on this vertex */
1227 rv
= labelcl_info_get_LBL(de
, INFO_LBL_INVENT
,
1228 NULL
, (arbitrary_info_t
*)&pinv
);
1229 if (rv
!= LABELCL_SUCCESS
)
1230 return(LABELCL_NOT_FOUND
);
1233 /* Advance to next item on this vertex */
1234 pinv
= place
->invplace_inv
->inv_next
;
1236 place
->invplace_inv
= pinv
;
1239 return(LABELCL_SUCCESS
);
1243 * hwgraph_controller_num_get - Returns the controller number in the inventory
1247 hwgraph_controller_num_get(devfs_handle_t device
)
1250 invplace_t invplace
= { NULL
, NULL
, NULL
};
1252 if ((pinv
= device_inventory_get_next(device
, &invplace
)) != NULL
) {
1253 val
= (pinv
->inv_class
== INV_NETWORK
)? pinv
->inv_unit
: pinv
->inv_controller
;
1257 * It does not make any sense to call this on vertexes with multiple
1258 * inventory structs chained together
1260 if ( device_inventory_get_next(device
, &invplace
) != NULL
) {
1261 printk("Should panic here ... !\n");
1267 * hwgraph_controller_num_set - Sets the controller number in the inventory
1271 hwgraph_controller_num_set(devfs_handle_t device
, int contr_num
)
1274 invplace_t invplace
= { NULL
, NULL
, NULL
};
1275 if ((pinv
= device_inventory_get_next(device
, &invplace
)) != NULL
) {
1276 if (pinv
->inv_class
== INV_NETWORK
)
1277 pinv
->inv_unit
= contr_num
;
1279 if (pinv
->inv_class
== INV_FCNODE
)
1280 pinv
= device_inventory_get_next(device
, &invplace
);
1282 pinv
->inv_controller
= contr_num
;
1287 * It does not make any sense to call this on vertexes with multiple
1288 * inventory structs chained together
1291 ASSERT(device_inventory_get_next(device
, &invplace
) == NULL
);
1296 * Find the canonical name for a given vertex by walking back through
1297 * connectpt's until we hit the hwgraph root vertex (or until we run
1298 * out of buffer space or until something goes wrong).
1300 * COMPATIBILITY FUNCTIONALITY
1301 * Walks back through 'parents', not necessarily the same as connectpts.
1303 * Need to resolve the fact that devfs does not return the path from
1304 * "/" but rather it just stops right before /dev ..
1307 hwgraph_vertex_name_get(devfs_handle_t vhdl
, char *buf
, uint buflen
)
1313 return(-1); /* XXX should be GRAPH_BAD_PARAM ? */
1315 locbuf
= kmalloc(buflen
, GFP_KERNEL
);
1317 pos
= devfs_generate_path(vhdl
, locbuf
, buflen
);
1323 strcpy(buf
, &locbuf
[pos
]);
1329 ** vertex_to_name converts a vertex into a canonical name by walking
1330 ** back through connect points until we hit the hwgraph root (or until
1331 ** we run out of buffer space).
1333 ** Usually returns a pointer to the original buffer, filled in as
1334 ** appropriate. If the buffer is too small to hold the entire name,
1335 ** or if anything goes wrong while determining the name, vertex_to_name
1336 ** returns "UnknownDevice".
1339 #define DEVNAME_UNKNOWN "UnknownDevice"
1342 vertex_to_name(devfs_handle_t vhdl
, char *buf
, uint buflen
)
1344 if (hwgraph_vertex_name_get(vhdl
, buf
, buflen
) == GRAPH_SUCCESS
)
1347 return(DEVNAME_UNKNOWN
);
1352 ** Return the compact node id of the node that ultimately "owns" the specified
1353 ** vertex. In order to do this, we walk back through masters and connect points
1354 ** until we reach a vertex that represents a node.
1357 master_node_get(devfs_handle_t vhdl
)
1360 devfs_handle_t master
;
1363 cnodeid
= nodevertex_to_cnodeid(vhdl
);
1364 if (cnodeid
!= CNODEID_NONE
)
1367 master
= device_master_get(vhdl
);
1369 /* Check for exceptional cases */
1370 if (master
== vhdl
) {
1371 /* Since we got a reference to the "master" thru
1372 * device_master_get() we should decrement
1373 * its reference count by 1
1375 hwgraph_vertex_unref(master
);
1376 return(CNODEID_NONE
);
1379 if (master
== GRAPH_VERTEX_NONE
) {
1380 master
= hwgraph_connectpt_get(vhdl
);
1381 if ((master
== GRAPH_VERTEX_NONE
) ||
1384 /* Since we got a reference to the
1386 * hwgraph_connectpt_get() we should
1387 * decrement its reference count by 1
1389 hwgraph_vertex_unref(master
);
1390 return(CNODEID_NONE
);
1395 /* Decrement the reference to "master" which was got
1396 * either thru device_master_get() or hwgraph_connectpt_get()
1399 hwgraph_vertex_unref(master
);
1404 * Using the canonical path name to get hold of the desired vertex handle will
1405 * not work on multi-hub sn0 nodes. Hence, we use the following (slightly
1406 * convoluted) algorithm.
1408 * - Start at the vertex corresponding to the driver (provided as input parameter)
1409 * - Loop till you reach a vertex which has EDGE_LBL_MEMORY
1410 * - If EDGE_LBL_CONN exists, follow that up.
1411 * else if EDGE_LBL_MASTER exists, follow that up.
1412 * else follow EDGE_LBL_DOTDOT up.
1414 * * We should be at desired hub/heart vertex now *
1415 * - Follow EDGE_LBL_CONN to the widget vertex.
1417 * - return vertex handle of this widget.
1420 mem_vhdl_get(devfs_handle_t drv_vhdl
)
1422 devfs_handle_t cur_vhdl
, cur_upper_vhdl
;
1423 devfs_handle_t tmp_mem_vhdl
, mem_vhdl
;
1424 graph_error_t loop_rv
;
1426 /* Initializations */
1427 cur_vhdl
= drv_vhdl
;
1428 loop_rv
= ~GRAPH_SUCCESS
;
1430 /* Loop till current vertex has EDGE_LBL_MEMORY */
1431 while (loop_rv
!= GRAPH_SUCCESS
) {
1433 if ((hwgraph_edge_get(cur_vhdl
, EDGE_LBL_CONN
, &cur_upper_vhdl
)) == GRAPH_SUCCESS
) {
1435 } else if ((hwgraph_edge_get(cur_vhdl
, EDGE_LBL_MASTER
, &cur_upper_vhdl
)) == GRAPH_SUCCESS
) {
1436 } else { /* Follow HWGRAPH_EDGELBL_DOTDOT up */
1437 (void) hwgraph_edge_get(cur_vhdl
, HWGRAPH_EDGELBL_DOTDOT
, &cur_upper_vhdl
);
1440 cur_vhdl
= cur_upper_vhdl
;
1442 #if DEBUG && HWG_DEBUG
1443 printf("Current vhdl %d \n", cur_vhdl
);
1446 loop_rv
= hwgraph_edge_get(cur_vhdl
, EDGE_LBL_MEMORY
, &tmp_mem_vhdl
);
1449 /* We should be at desired hub/heart vertex now */
1450 if ((hwgraph_edge_get(cur_vhdl
, EDGE_LBL_CONN
, &mem_vhdl
)) != GRAPH_SUCCESS
)
1451 return (GRAPH_VERTEX_NONE
);
1459 ** Add a char device -- if the driver supports it -- at a specified vertex.
1462 hwgraph_char_device_add( devfs_handle_t from
,
1465 devfs_handle_t
*devhdl
)
1467 devfs_handle_t xx
= NULL
;
1469 printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n");
1470 *devhdl
= xx
; // Must set devhdl
1471 return(GRAPH_SUCCESS
);
1475 hwgraph_edge_remove(devfs_handle_t from
, char *name
, devfs_handle_t
*toptr
)
1477 printk("WARNING: hwgraph_edge_remove NOT supported.\n");
1478 return(GRAPH_ILLEGAL_REQUEST
);
1482 hwgraph_vertex_unref(devfs_handle_t vhdl
)
1484 return(GRAPH_ILLEGAL_REQUEST
);
1488 EXPORT_SYMBOL(hwgraph_mk_dir
);
1489 EXPORT_SYMBOL(hwgraph_path_add
);
1490 EXPORT_SYMBOL(hwgraph_char_device_add
);
1491 EXPORT_SYMBOL(hwgraph_register
);
1492 EXPORT_SYMBOL(hwgraph_vertex_destroy
);
1494 EXPORT_SYMBOL(hwgraph_fastinfo_get
);
1495 EXPORT_SYMBOL(hwgraph_edge_get
);
1497 EXPORT_SYMBOL(hwgraph_fastinfo_set
);
1498 EXPORT_SYMBOL(hwgraph_connectpt_set
);
1499 EXPORT_SYMBOL(hwgraph_connectpt_get
);
1500 EXPORT_SYMBOL(hwgraph_edge_get_next
);
1501 EXPORT_SYMBOL(hwgraph_info_add_LBL
);
1502 EXPORT_SYMBOL(hwgraph_info_remove_LBL
);
1503 EXPORT_SYMBOL(hwgraph_info_replace_LBL
);
1504 EXPORT_SYMBOL(hwgraph_info_get_LBL
);
1505 EXPORT_SYMBOL(hwgraph_info_get_exported_LBL
);
1506 EXPORT_SYMBOL(hwgraph_info_get_next_LBL
);
1507 EXPORT_SYMBOL(hwgraph_info_export_LBL
);
1508 EXPORT_SYMBOL(hwgraph_info_unexport_LBL
);
1509 EXPORT_SYMBOL(hwgraph_path_lookup
);
1510 EXPORT_SYMBOL(hwgraph_traverse
);
1511 EXPORT_SYMBOL(hwgraph_path_to_vertex
);
1512 EXPORT_SYMBOL(hwgraph_path_to_dev
);
1513 EXPORT_SYMBOL(hwgraph_block_device_get
);
1514 EXPORT_SYMBOL(hwgraph_char_device_get
);
1515 EXPORT_SYMBOL(hwgraph_vertex_name_get
);