patch-2.4.22 linux-2.4.22/arch/ia64/sn/io/hcl.c

Next file: linux-2.4.22/arch/ia64/sn/io/hcl_util.c
Previous file: linux-2.4.22/arch/ia64/sn/io/efi-rtc.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/arch/ia64/sn/io/hcl.c linux-2.4.22/arch/ia64/sn/io/hcl.c
@@ -1,1531 +0,0 @@
-/* $Id$
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- *  hcl - SGI's Hardware Graph compatibility layer.
- *
- * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <asm/sn/sgi.h>
-#include <linux/devfs_fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <asm/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/invent.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-
-#define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER"
-#define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE"
-#define HCL_TEMP_NAME_LEN 44 
-#define HCL_VERSION "1.0"
-devfs_handle_t hwgraph_root = NULL;
-devfs_handle_t linux_busnum = NULL;
-
-/*
- * Debug flag definition.
- */
-#define OPTION_NONE             0x00
-#define HCL_DEBUG_NONE 0x00000
-#define HCL_DEBUG_ALL  0x0ffff
-#if defined(CONFIG_HCL_DEBUG)
-static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE;
-#endif
-static unsigned int hcl_debug = HCL_DEBUG_NONE;
-#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
-static unsigned int boot_options = OPTION_NONE;
-#endif
-
-/*
- * Some Global definitions.
- */
-devfs_handle_t hcl_handle = NULL;
-
-invplace_t invplace_none = {
-	GRAPH_VERTEX_NONE,
-	GRAPH_VERTEX_PLACE_NONE,
-	NULL
-};
-
-/*
- * HCL device driver.
- * The purpose of this device driver is to provide a facility 
- * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path 
- * to manipulate label entries without having to implement
- * system call interfaces.  This methodology will enable us to 
- * make this feature module loadable.
- */
-static int hcl_open(struct inode * inode, struct file * filp)
-{
-	if (hcl_debug) {
-        	printk("HCL: hcl_open called.\n");
-	}
-
-        return(0);
-
-}
-
-static int hcl_close(struct inode * inode, struct file * filp)
-{
-
-	if (hcl_debug) {
-        	printk("HCL: hcl_close called.\n");
-	}
-
-        return(0);
-
-}
-
-static int hcl_ioctl(struct inode * inode, struct file * file,
-        unsigned int cmd, unsigned long arg)
-{
-
-	if (hcl_debug) {
-		printk("HCL: hcl_ioctl called.\n");
-	}
-
-	switch (cmd) {
-		default:
-			if (hcl_debug) {
-				printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd);
-			}
-	}
-
-	return(0);
-
-}
-
-struct file_operations hcl_fops = {
-	(struct module *)0,
-	NULL,		/* lseek - default */
-	NULL,		/* read - general block-dev read */
-	NULL,		/* write - general block-dev write */
-	NULL,		/* readdir - bad */
-	NULL,		/* poll */
-	hcl_ioctl,      /* ioctl */
-	NULL,		/* mmap */
-	hcl_open,	/* open */
-	NULL,		/* flush */
-	hcl_close,	/* release */
-	NULL,		/* fsync */
-	NULL,		/* fasync */
-	NULL,		/* lock */
-	NULL,		/* readv */
-	NULL,		/* writev */
-};
-
-
-/*
- * init_hcl() - Boot time initialization.  Ensure that it is called 
- *	after devfs has been initialized.
- *
- * For now this routine is being called out of devfs/base.c.  Actually 
- * Not a bad place to be ..
- *
- */
-#ifdef MODULE
-int init_module (void)
-#else
-int __init init_hcl(void)
-#endif
-{
-	extern void string_table_init(struct string_table *);
-	extern struct string_table label_string_table;
-	extern int init_ifconfig_net(void);
-	int rv = 0;
-
-#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
-	printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n",
-		HCL_NAME, HCL_VERSION);
-
-	hcl_debug = hcl_debug_init;
-	printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME, hcl_debug);
-	printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options);
-#endif
-
-	/*
-	 * Create the hwgraph_root on devfs.
-	 */
-	rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root);
-	if (rv)
-		printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv);
-
-	/*
-	 * Create the hcl driver to support inventory entry manipulations.
-	 * By default, it is expected that devfs is mounted on /dev.
-	 *
-	 */
-	hcl_handle = hwgraph_register(hwgraph_root, ".hcl",
-			0, DEVFS_FL_AUTO_DEVNUM,
-			0, 0,
-			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
-			&hcl_fops, NULL);
-
-	if (hcl_handle == NULL) {
-		panic("HCL: Unable to create HCL Driver in init_hcl().\n");
-		return(0);
-	}
-
-	/*
-	 * Initialize the HCL string table.
-	 */
-	string_table_init(&label_string_table);
-
-	/*
-	 * Create the directory that links Linux bus numbers to our Xwidget.
-	 */
-	rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum);
-	if (linux_busnum == NULL) {
-		panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS);
-		return(0);
-	}
-
-	/*
-	 * Initialize the ifconfgi_net driver that does network devices 
-	 * Persistent Naming.
-	 */
-	init_ifconfig_net();
-
-	return(0);
-
-}
-
-
-/*
- * hcl_setup() - Process boot time parameters if given.
- *	"hcl="
- *	This routine gets called only if "hcl=" is given in the 
- *	boot line and before init_hcl().
- *
- *	We currently do not have any boot options .. when we do, 
- *	functionalities can be added here.
- *
- */
-static int __init hcl_setup(char *str)
-{
-    while ( (*str != '\0') && !isspace (*str) )
-    {
-#ifdef CONFIG_HCL_DEBUG
-        if (strncmp (str, "all", 3) == 0) {
-            hcl_debug_init |= HCL_DEBUG_ALL;
-            str += 3;
-        } else 
-        	return 0;
-#endif
-        if (*str != ',') return 0;
-        ++str;
-    }
-
-    return 1;
-
-}
-
-__setup("hcl=", hcl_setup);
-
-
-/*
- * Set device specific "fast information".
- *
- */
-void
-hwgraph_fastinfo_set(devfs_handle_t de, arbitrary_info_t fastinfo)
-{
-
-	if (hcl_debug) {
-		printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ld\n", (void *)de, fastinfo);
-	}
-		
-	labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL);
-
-}
-
-
-/*
- * Get device specific "fast information".
- *
- */
-arbitrary_info_t
-hwgraph_fastinfo_get(devfs_handle_t de)
-{
-	arbitrary_info_t fastinfo;
-	int rv;
-
-	if (!de) {
-		printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n");
-		return(-1);
-	}
-
-	rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo);
-	if (rv == 0)
-		return(fastinfo);
-
-	return(0);
-}
-
-
-/*
- * hwgraph_connectpt_set - Sets the connect point handle in de to the 
- *	given connect_de handle.  By default, the connect point of the 
- *	devfs node is the parent.  This effectively changes this assumption.
- */
-int
-hwgraph_connectpt_set(devfs_handle_t de, devfs_handle_t connect_de)
-{
-	int rv;
-
-	if (!de)
-		return(-1);
-
-	rv = labelcl_info_connectpt_set(de, connect_de);
-
-	return(rv);
-}
-
-
-/*
- * hwgraph_connectpt_get: Returns the entry's connect point  in the devfs 
- *	tree.
- */
-devfs_handle_t
-hwgraph_connectpt_get(devfs_handle_t de)
-{
-	int rv;
-	arbitrary_info_t info;
-	devfs_handle_t connect;
-
-	rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
-	if (rv != 0) {
-		return(NULL);
-	}
-
-	connect = (devfs_handle_t)info;
-	return(connect);
-
-}
-
-
-/*
- * hwgraph_mk_dir - Creates a directory entry with devfs.
- *	Note that a directory entry in devfs can have children 
- *	but it cannot be a char|block special file.
- */
-devfs_handle_t
-hwgraph_mk_dir(devfs_handle_t de, const char *name,
-                unsigned int namelen, void *info)
-{
-
-	int rv;
-	labelcl_info_t *labelcl_info = NULL;
-	devfs_handle_t new_devfs_handle = NULL;
-	devfs_handle_t parent = NULL;
-
-	/*
-	 * Create the device info structure for hwgraph compatiblity support.
-	 */
-	labelcl_info = labelcl_info_create();
-	if (!labelcl_info)
-		return(NULL);
-
-	/*
-	 * Create a devfs entry.
-	 */
-	new_devfs_handle = devfs_mk_dir(de, name, (void *)labelcl_info);
-	if (!new_devfs_handle) {
-		labelcl_info_destroy(labelcl_info);
-		return(NULL);
-	}
-
-	/*
-	 * Get the parent handle.
-	 */
-	parent = devfs_get_parent (new_devfs_handle);
-
-	/*
-	 * To provide the same semantics as the hwgraph, set the connect point.
-	 */
-	rv = hwgraph_connectpt_set(new_devfs_handle, parent);
-	if (!rv) {
-		/*
-		 * We need to clean up!
-		 */
-	}
-
-	/*
-	 * If the caller provides a private data pointer, save it in the 
-	 * labelcl info structure(fastinfo).  This can be retrieved via
-	 * hwgraph_fastinfo_get()
-	 */
-	if (info)
-		hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info);
-		
-	return(new_devfs_handle);
-
-}
-
-/*
- * hwgraph_vertex_create - Create a vertex by giving it a temp name.
- */
-
-/*
- * hwgraph_path_add - Create a directory node with the given path starting 
- * from the given devfs_handle_t.
- */
-extern char * dev_to_name(devfs_handle_t, char *, uint);
-int
-hwgraph_path_add(devfs_handle_t  fromv,
-		 char *path,
-		 devfs_handle_t *new_de)
-{
-
-	unsigned int	namelen = strlen(path);
-	int		rv;
-
-	/*
-	 * We need to handle the case when fromv is NULL ..
-	 * in this case we need to create the path from the 
-	 * hwgraph root!
-	 */
-	if (fromv == NULL)
-		fromv = hwgraph_root;
-
-	/*
-	 * check the entry doesn't already exist, if it does
-	 * then we simply want new_de to point to it (otherwise
-	 * we'll overwrite the existing labelcl_info struct)
-	 */
-	rv = hwgraph_edge_get(fromv, path, new_de);
-	if (rv)	{	/* couldn't find entry so we create it */
-		*new_de = hwgraph_mk_dir(fromv, path, namelen, NULL);
-		if (new_de == NULL)
-			return(-1);
-		else
-			return(0);
-	}
-	else 
- 		return(0);
-
-}
-
-/*
- * hwgraph_register  - Creates a file entry with devfs.
- *	Note that a file entry cannot have children .. it is like a 
- *	char|block special vertex in hwgraph.
- */
-devfs_handle_t
-hwgraph_register(devfs_handle_t de, const char *name,
-                unsigned int namelen, unsigned int flags, 
-		unsigned int major, unsigned int minor,
-                umode_t mode, uid_t uid, gid_t gid, 
-		struct file_operations *fops,
-                void *info)
-{
-
-	int rv;
-        void *labelcl_info = NULL;
-        devfs_handle_t new_devfs_handle = NULL;
-	devfs_handle_t parent = NULL;
-
-        /*
-         * Create the labelcl info structure for hwgraph compatiblity support.
-         */
-        labelcl_info = labelcl_info_create();
-        if (!labelcl_info)
-                return(NULL);
-
-        /*
-         * Create a devfs entry.
-         */
-        new_devfs_handle = devfs_register(de, name, flags, major,
-				minor, mode, fops, labelcl_info);
-        if (!new_devfs_handle) {
-                labelcl_info_destroy((labelcl_info_t *)labelcl_info);
-                return(NULL);
-        }
-
-	/*
-	 * Get the parent handle.
-	 */
-	if (de == NULL)
-		parent = devfs_get_parent (new_devfs_handle);
-	else
-		parent = de;
-		
-	/*
-	 * To provide the same semantics as the hwgraph, set the connect point.
-	 */
-	rv = hwgraph_connectpt_set(new_devfs_handle, parent);
-	if (rv) {
-		/*
-		 * We need to clean up!
-		 */
-		printk(KERN_WARNING "HCL: Unable to set the connect point to it's parent 0x%p\n",
-			(void *)new_devfs_handle);
-	}
-
-        /*
-         * If the caller provides a private data pointer, save it in the 
-         * labelcl info structure(fastinfo).  This can be retrieved via
-         * hwgraph_fastinfo_get()
-         */
-        if (info)
-                hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info);
-
-        return(new_devfs_handle);
-
-}
-
-
-/*
- * hwgraph_mk_symlink - Create a symbolic link.
- */
-int
-hwgraph_mk_symlink(devfs_handle_t de, const char *name, unsigned int namelen,
-                unsigned int flags, const char *link, unsigned int linklen, 
-		devfs_handle_t *handle, void *info)
-{
-
-	void *labelcl_info = NULL;
-	int status = 0;
-	devfs_handle_t new_devfs_handle = NULL;
-
-	/*
-	 * Create the labelcl info structure for hwgraph compatiblity support.
-	 */
-	labelcl_info = labelcl_info_create();
-	if (!labelcl_info)
-		return(-1);
-
-	/*
-	 * Create a symbolic link devfs entry.
-	 */
-	status = devfs_mk_symlink(de, name, flags, link,
-				&new_devfs_handle, labelcl_info);
-	if ( (!new_devfs_handle) || (!status) ){
-		labelcl_info_destroy((labelcl_info_t *)labelcl_info);
-		return(-1);
-	}
-
-	/*
-	 * If the caller provides a private data pointer, save it in the 
-	 * labelcl info structure(fastinfo).  This can be retrieved via
-	 * hwgraph_fastinfo_get()
-	 */
-	if (info)
-		hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info);
-
-	*handle = new_devfs_handle;
-	return(0);
-
-}
-
-/*
- * hwgraph_vertex_get_next - this routine returns the next sibbling for the 
- *	device entry given in de.  If there are no more sibbling, NULL 
- * 	is returned in next_sibbling.
- *
- *	Currently we do not have any protection against de being deleted 
- *	while it's handle is being held.
- */
-int
-hwgraph_vertex_get_next(devfs_handle_t *next_sibbling, devfs_handle_t *de)
-{
-	*next_sibbling = devfs_get_next_sibling (*de);
-
-	if (*next_sibbling != NULL)
-		*de = *next_sibbling;
-	return (0);
-}
-
-
-/*
- * hwgraph_vertex_destroy - Destroy the devfs entry
- */
-int
-hwgraph_vertex_destroy(devfs_handle_t de)
-{
-
-	void *labelcl_info = NULL;
-
-	labelcl_info = devfs_get_info(de);
-	devfs_unregister(de);
-
-	if (labelcl_info)
-		labelcl_info_destroy((labelcl_info_t *)labelcl_info);
-
-	return(0);
-}
-
-/*
-** See if a vertex has an outgoing edge with a specified name.
-** Vertices in the hwgraph *implicitly* contain these edges:
-**	"." 	refers to "current vertex"
-**	".." 	refers to "connect point vertex"
-**	"char"	refers to current vertex (character device access)
-**	"block"	refers to current vertex (block device access)
-*/
-
-/*
- * hwgraph_edge_add - This routines has changed from the original conext.
- * All it does now is to create a symbolic link from "from" to "to".
- */
-/* ARGSUSED */
-int
-hwgraph_edge_add(devfs_handle_t from, devfs_handle_t to, char *name)
-{
-
-	char *path;
-	char *s1;
-	char *index;
-	int name_start;
-	devfs_handle_t handle = NULL;
-	int rv;
-	int i, count;
-
-	path = kmalloc(1024, GFP_KERNEL);
-	memset(path, 0x0, 1024);
-	name_start = devfs_generate_path (from, path, 1024);
-	s1 = &path[name_start];
-	count = 0;
-	while (1) {
-		index = strstr (s1, "/");
-		if (index) {
-			count++;
-			s1 = ++index;
-		} else {
-			count++;
-			break;
-		}
-	}
-
-	memset(path, 0x0, 1024);
-	name_start = devfs_generate_path (to, path, 1024);
-
-	for (i = 0; i < count; i++) {
-		strcat(path,"../");
-	}
-
-	strcat(path, &path[name_start]);
-
-	/*
-	 * Otherwise, just create a symlink to the vertex.
-	 * In this case the vertex was previous created with a REAL pathname.
-	 */
-	rv = devfs_mk_symlink (from, (const char *)name, 
-			       DEVFS_FL_DEFAULT, path,
-			       &handle, NULL);
-
-	name_start = devfs_generate_path (handle, path, 1024);
-	return(rv);
-
-	
-}
-/* ARGSUSED */
-int
-hwgraph_edge_get(devfs_handle_t from, char *name, devfs_handle_t *toptr)
-{
-
-	int namelen = 0;
-	devfs_handle_t target_handle = NULL;
-
-	if (name == NULL)
-		return(-1);
-
-	if (toptr == NULL)
-		return(-1);
-
-	/*
-	 * If the name is "." just return the current devfs entry handle.
-	 */
-	if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) {
-		if (toptr) {
-			*toptr = from;
-		}
-	} else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) {
-		/*
-		 * Hmmm .. should we return the connect point or parent ..
-		 * see in hwgraph, the concept of parent is the connectpt!
-		 *
-		 * Maybe we should see whether the connectpt is set .. if 
-		 * not just return the parent!
-		 */
-		target_handle = hwgraph_connectpt_get(from);
-		if (target_handle) {
-			/*
-			 * Just return the connect point.
-			 */
-			*toptr = target_handle;
-			return(0);
-		}
-		target_handle = devfs_get_parent(from);
-		*toptr = target_handle;
-
-	} else {
-		/*
-		 * Call devfs to get the devfs entry.
-		 */
-		namelen = (int) strlen(name);
-		target_handle = devfs_find_handle (from, name, 0, 0,
-					0, 1); /* Yes traverse symbolic links */
-		if (target_handle == NULL)
-			return(-1);
-		else
-		*toptr = target_handle;
-	}
-
-	return(0);
-}
-
-
-/*
- * hwgraph_edge_get_next - Retrieves the next sibbling given the current
- *	entry number "placeptr".
- *
- * 	Allow the caller to retrieve walk through the sibblings of "source" 
- * 	devfs_handle_t.  The implicit edges "." and ".." is returned first 
- * 	followed by each of the real children.
- *
- *	We may end up returning garbage if another thread perform any deletion 
- *	in this directory before "placeptr".
- *
- */
-/* ARGSUSED */
-int
-hwgraph_edge_get_next(devfs_handle_t source, char *name, devfs_handle_t *target,
-                              uint *placeptr)
-
-{
-
-        uint which_place;
-	unsigned int namelen = 0;
-	const char *tempname = NULL;
-
-        if (placeptr == NULL)
-                return(-1);
-
-        which_place = *placeptr;
-
-again:
-        if (which_place <= HWGRAPH_RESERVED_PLACES) {
-                if (which_place == EDGE_PLACE_WANT_CURRENT) {
-			/*
-			 * Looking for "."
-			 * Return the current devfs handle.
-			 */
-                        if (name != NULL)
-                                strcpy(name, HWGRAPH_EDGELBL_DOT);
-
-                        if (target != NULL) {
-                                *target = source; 
-				/* XXX should incr "source" ref count here if we
-				 * ever implement ref counts */
-                        }
-
-                } else if (which_place == EDGE_PLACE_WANT_CONNECTPT) {
-			/*
-			 * Looking for the connect point or parent.
-			 * If the connect point is set .. it returns the connect point.
-			 * Otherwise, it returns the parent .. will we support 
-			 * connect point?
-			 */
-                        devfs_handle_t connect_point = hwgraph_connectpt_get(source);
-
-                        if (connect_point == NULL) {
-				/*
-				 * No connectpoint set .. either the User
-				 * explicitly NULL it or this node was not 
-				 * created via hcl.
-				 */
-                                which_place++;
-                                goto again;
-                        }
-
-                        if (name != NULL)
-                                strcpy(name, HWGRAPH_EDGELBL_DOTDOT);
-
-                        if (target != NULL)
-                                *target = connect_point;
-
-                } else if (which_place == EDGE_PLACE_WANT_REAL_EDGES) {
-			/* 
-			 * return first "real" entry in directory, and increment
-			 * placeptr.  Next time around we should have 
-			 * which_place > HWGRAPH_RESERVED_EDGES so we'll fall through
-			 * this nested if block.
-			 */
-			*target = devfs_get_first_child(source);
-			if (*target && name) {
-				tempname = devfs_get_name(*target, &namelen);
-				if (tempname && namelen)
-					strcpy(name, tempname);
-			}
-					
-			*placeptr = which_place + 1;
-			return (0);
-                }
-
-                *placeptr = which_place+1;
-                return(0);
-        }
-
-	/*
-	 * walk linked list, (which_place - HWGRAPH_RESERVED_PLACES) times
-	 */
-	{
-		devfs_handle_t	curr;
-		int		i = 0;
-
-		for (curr=devfs_get_first_child(source), i= i+HWGRAPH_RESERVED_PLACES; 
-			curr!=NULL && i<which_place; 
-			curr=devfs_get_next_sibling(curr), i++)
-			;
-		*target = curr;
-		*placeptr = which_place + 1;
-		if (curr && name) {
-			tempname = devfs_get_name(*target, &namelen);
-			if (tempname && namelen)
-				strcpy(name, tempname);
-		}
-	}
-	if (target == NULL)
-		return(-1);
-	else
-        	return(0);
-}
-
-/*
- * hwgraph_info_add_LBL - Adds a new label for the device.  Mark the info_desc
- *	of the label as INFO_DESC_PRIVATE and store the info in the label.
- */
-/* ARGSUSED */
-int
-hwgraph_info_add_LBL(	devfs_handle_t de,
-			char *name,
-			arbitrary_info_t info)
-{
-	return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info));
-}
-
-/*
- * hwgraph_info_remove_LBL - Remove the label entry for the device.
- */
-/* ARGSUSED */
-int
-hwgraph_info_remove_LBL(	devfs_handle_t de,
-				char *name,
-				arbitrary_info_t *old_info)
-{
-	return(labelcl_info_remove_LBL(de, name, NULL, old_info));
-}
-
-/*
- * hwgraph_info_replace_LBL - replaces an existing label with 
- *	a new label info value.
- */
-/* ARGSUSED */
-int
-hwgraph_info_replace_LBL(	devfs_handle_t de,
-				char *name,
-				arbitrary_info_t info,
-				arbitrary_info_t *old_info)
-{
-	return(labelcl_info_replace_LBL(de, name,
-			INFO_DESC_PRIVATE, info,
-			NULL, old_info));
-}
-/*
- * hwgraph_info_get_LBL - Get and return the info value in the label of the 
- * 	device.
- */
-/* ARGSUSED */
-int
-hwgraph_info_get_LBL(	devfs_handle_t de,
-			char *name,
-			arbitrary_info_t *infop)
-{
-	return(labelcl_info_get_LBL(de, name, NULL, infop));
-}
-
-/*
- * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer 
- *	of the given label for the device.  The weird thing is that the label 
- *	that matches the name is return irrespective of the info_desc value!
- *	Do not understand why the word "exported" is used!
- */
-/* ARGSUSED */
-int
-hwgraph_info_get_exported_LBL(	devfs_handle_t de,
-				char *name,
-				int *export_info,
-				arbitrary_info_t *infop)
-{
-	int rc;
-	arb_info_desc_t info_desc;
-
-	rc = labelcl_info_get_LBL(de, name, &info_desc, infop);
-	if (rc == 0)
-		*export_info = (int)info_desc;
-
-	return(rc);
-}
-
-/*
- * hwgraph_info_get_next_LBL - Returns the next label info given the 
- *	current label entry in place.
- *
- *	Once again this has no locking or reference count for protection.
- *
- */
-/* ARGSUSED */
-int
-hwgraph_info_get_next_LBL(	devfs_handle_t de,
-				char *buf,
-				arbitrary_info_t *infop,
-				labelcl_info_place_t *place)
-{
-	return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place));
-}
-
-/*
- * hwgraph_info_export_LBL - Retrieve the specified label entry and modify 
- *	the info_desc field with the given value in nbytes.
- */
-/* ARGSUSED */
-int
-hwgraph_info_export_LBL(devfs_handle_t de, char *name, int nbytes)
-{
-	arbitrary_info_t info;
-	int rc;
-
-	if (nbytes == 0)
-		nbytes = INFO_DESC_EXPORT;
-
-	if (nbytes < 0)
-		return(-1);
-
-	rc = labelcl_info_get_LBL(de, name, NULL, &info);
-	if (rc != 0)
-		return(rc);
-
-	rc = labelcl_info_replace_LBL(de, name,
-				nbytes, info, NULL, NULL);
-
-	return(rc);
-}
-
-/*
- * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the 
- * label info_descr filed to INFO_DESC_PRIVATE.
- */
-/* ARGSUSED */
-int
-hwgraph_info_unexport_LBL(devfs_handle_t de, char *name)
-{
-	arbitrary_info_t info;
-	int rc;
-
-	rc = labelcl_info_get_LBL(de, name, NULL, &info);
-	if (rc != 0)
-		return(rc);
-
-	rc = labelcl_info_replace_LBL(de, name,
-				INFO_DESC_PRIVATE, info, NULL, NULL);
-
-	return(rc);
-}
-
-/*
- * hwgraph_path_lookup - return the handle for the given path.
- *
- */
-int
-hwgraph_path_lookup(	devfs_handle_t start_vertex_handle,
-			char *lookup_path,
-			devfs_handle_t *vertex_handle_ptr,
-			char **remainder)
-{
-	*vertex_handle_ptr = devfs_find_handle(start_vertex_handle,	/* start dir */
-					lookup_path,		/* path */
-					0,			/* major */
-					0,			/* minor */
-					0,			/* char | block */
-					1);			/* traverse symlinks */
-	if (*vertex_handle_ptr == NULL)
-		return(-1);
-	else
-		return(0);
-}
-
-/*
- * hwgraph_traverse - Find and return the devfs handle starting from de.
- *
- */
-graph_error_t
-hwgraph_traverse(devfs_handle_t de, char *path, devfs_handle_t *found)
-{
-	/* 
-	 * get the directory entry (path should end in a directory)
-	 */
-
-	*found = devfs_find_handle(de,	/* start dir */
-			    path,	/* path */
-			    0,		/* major */
-			    0,		/* minor */
-			    0,		/* char | block */
-			    1);		/* traverse symlinks */
-	if (*found == NULL)
-		return(GRAPH_NOT_FOUND);
-	else
-		return(GRAPH_SUCCESS);
-}
-
-/*
- * hwgraph_path_to_vertex - Return the devfs entry handle for the given 
- *	pathname .. assume traverse symlinks too!.
- */
-devfs_handle_t
-hwgraph_path_to_vertex(char *path)
-{
-	return(devfs_find_handle(NULL,	/* start dir */
-			path,		/* path */
-		    	0,		/* major */
-		    	0,		/* minor */
-		    	0,		/* char | block */
-		    	1));		/* traverse symlinks */
-}
-
-/*
- * hwgraph_path_to_dev - Returns the devfs_handle_t of the given path ..
- *	We only deal with devfs handle and not devfs_handle_t.
-*/
-devfs_handle_t
-hwgraph_path_to_dev(char *path)
-{
-	devfs_handle_t  de;
-
-	de = hwgraph_path_to_vertex(path);
-	return(de);
-}
-
-/*
- * hwgraph_block_device_get - return the handle of the block device file.
- *	The assumption here is that de is a directory.
-*/
-devfs_handle_t
-hwgraph_block_device_get(devfs_handle_t de)
-{
-	return(devfs_find_handle(de,		/* start dir */
-			"block",		/* path */
-		    	0,			/* major */
-		    	0,			/* minor */
-		    	DEVFS_SPECIAL_BLK,	/* char | block */
-		    	1));			/* traverse symlinks */
-}
-
-/*
- * hwgraph_char_device_get - return the handle of the char device file.
- *      The assumption here is that de is a directory.
-*/
-devfs_handle_t
-hwgraph_char_device_get(devfs_handle_t de)
-{
-	return(devfs_find_handle(de,		/* start dir */
-			"char",			/* path */
-		    	0,			/* major */
-		    	0,			/* minor */
-		    	DEVFS_SPECIAL_CHR,	/* char | block */
-		    	1));			/* traverse symlinks */
-}
-
-/*
-** Inventory is now associated with a vertex in the graph.  For items that
-** belong in the inventory but have no vertex 
-** (e.g. old non-graph-aware drivers), we create a bogus vertex under the 
-** INFO_LBL_INVENT name.
-**
-** For historical reasons, we prevent exact duplicate entries from being added
-** to a single vertex.
-*/
-
-/*
- * hwgraph_inventory_add - Adds an inventory entry into de.
- */
-int
-hwgraph_inventory_add(	devfs_handle_t de,
-			int class,
-			int type,
-			major_t controller,
-			minor_t unit,
-			int state)
-{
-	inventory_t *pinv = NULL, *old_pinv = NULL, *last_pinv = NULL;
-	int rv;
-
-	/*
-	 * Add our inventory data to the list of inventory data
-	 * associated with this vertex.
-	 */
-again:
-	/* GRAPH_LOCK_UPDATE(&invent_lock); */
-	rv = labelcl_info_get_LBL(de,
-			INFO_LBL_INVENT,
-			NULL, (arbitrary_info_t *)&old_pinv);
-	if ((rv != LABELCL_SUCCESS) && (rv != LABELCL_NOT_FOUND))
-		goto failure;
-
-	/*
-	 * Seek to end of inventory items associated with this
-	 * vertex.  Along the way, make sure we're not duplicating
-	 * an inventory item (for compatibility with old add_to_inventory)
-	 */
-	for (;old_pinv; last_pinv = old_pinv, old_pinv = old_pinv->inv_next) {
-		if ((int)class != -1 && old_pinv->inv_class != class)
-			continue;
-		if ((int)type != -1 && old_pinv->inv_type != type)
-			continue;
-		if ((int)state != -1 && old_pinv->inv_state != state)
-			continue;
-		if ((int)controller != -1
-		    && old_pinv->inv_controller != controller)
-			continue;
-		if ((int)unit != -1 && old_pinv->inv_unit != unit)
-			continue;
-
-		/* exact duplicate of previously-added inventory item */
-		rv = LABELCL_DUP;
-		goto failure;
-	}
-
-	/* Not a duplicate, so we know that we need to add something. */
-	if (pinv == NULL) {
-		/* Release lock while we wait for memory. */
-		/* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
-		pinv = (inventory_t *)kmalloc(sizeof(inventory_t), GFP_KERNEL);
-		replace_in_inventory(pinv, class, type, controller, unit, state);
-		goto again;
-	}
-
-	pinv->inv_next = NULL;
-	if (last_pinv) {
-		last_pinv->inv_next = pinv;
-	} else {
-		rv = labelcl_info_add_LBL(de, INFO_LBL_INVENT, 
-			sizeof(inventory_t), (arbitrary_info_t)pinv);
-
-		if (!rv)
-			goto failure;
-	}
-
-	/* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
-	return(0);
-
-failure:
-	/* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
-	if (pinv)
-		kfree(pinv);
-	return(rv);
-}
-
-
-/*
- * hwgraph_inventory_remove - Removes an inventory entry.
- *
- *	Remove an inventory item associated with a vertex.   It is the caller's
- *	responsibility to make sure that there are no races between removing
- *	inventory from a vertex and simultaneously removing that vertex.
-*/
-int
-hwgraph_inventory_remove(	devfs_handle_t de,
-				int class,
-				int type,
-				major_t controller,
-				minor_t unit,
-				int state)
-{
-	inventory_t *pinv = NULL, *last_pinv = NULL, *next_pinv = NULL;
-	labelcl_error_t rv;
-
-	/*
-	 * We never remove stuff from ".invent" ..
-	 */
-	if (!de)
-		return (-1);
-
-	/*
-	 * Remove our inventory data to the list of inventory data
-	 * associated with this vertex.
-	 */
-	/* GRAPH_LOCK_UPDATE(&invent_lock); */
-	rv = labelcl_info_get_LBL(de,
-			INFO_LBL_INVENT,
-			NULL, (arbitrary_info_t *)&pinv);
-	if (rv != LABELCL_SUCCESS)
-		goto failure;
-
-	/*
-	 * Search through inventory items associated with this
-	 * vertex, looking for a match.
-	 */
-	for (;pinv; pinv = next_pinv) {
-		next_pinv = pinv->inv_next;
-
-		if(((int)class == -1 || pinv->inv_class == class) &&
-		   ((int)type == -1 || pinv->inv_type == type) &&
-		   ((int)state == -1 || pinv->inv_state == state) &&
-		   ((int)controller == -1 || pinv->inv_controller == controller) &&
-		   ((int)unit == -1 || pinv->inv_unit == unit)) {
-
-			/* Found a matching inventory item. Remove it. */
-			if (last_pinv) {
-				last_pinv->inv_next = pinv->inv_next;
-			} else {
-				rv = hwgraph_info_replace_LBL(de, INFO_LBL_INVENT, (arbitrary_info_t)pinv->inv_next, NULL);
-				if (rv != LABELCL_SUCCESS)
-					goto failure;
-			}
-
-			pinv->inv_next = NULL; /* sanity */
-			kfree(pinv);
-		} else
-			last_pinv = pinv;
-	}
-
-	if (last_pinv == NULL) {
-		rv = hwgraph_info_remove_LBL(de, INFO_LBL_INVENT, NULL);
-		if (rv != LABELCL_SUCCESS)
-			goto failure;
-	}
-
-	rv = LABELCL_SUCCESS;
-
-failure:
-	/* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
-	return(rv);
-}
-
-/*
- * hwgraph_inventory_get_next - Get next inventory item associated with the 
- *	specified vertex.
- *
- *	No locking is really needed.  We don't yet have the ability
- *	to remove inventory items, and new items are always added to
- *	the end of a vertex' inventory list.
- *
- * 	However, a devfs entry can be removed!
-*/
-int
-hwgraph_inventory_get_next(devfs_handle_t de, invplace_t *place, inventory_t **ppinv)
-{
-	inventory_t *pinv;
-	labelcl_error_t rv;
-
-	if (de == NULL)
-		return(LABELCL_BAD_PARAM);
-
-	if (place->invplace_vhdl == NULL) {
-		place->invplace_vhdl = de;
-		place->invplace_inv = NULL;
-	}
-
-	if (de != place->invplace_vhdl)
-		return(LABELCL_BAD_PARAM);
-
-	if (place->invplace_inv == NULL) {
-		/* Just starting on this vertex */
-		rv = labelcl_info_get_LBL(de, INFO_LBL_INVENT,
-						NULL, (arbitrary_info_t *)&pinv);
-		if (rv != LABELCL_SUCCESS)
-			return(LABELCL_NOT_FOUND);
-
-	} else {
-		/* Advance to next item on this vertex */
-		pinv = place->invplace_inv->inv_next;
-	}
-	place->invplace_inv = pinv;
-	*ppinv = pinv;
-
-	return(LABELCL_SUCCESS);
-}
-
-/*
- * hwgraph_controller_num_get - Returns the controller number in the inventory 
- *	entry.
- */
-int
-hwgraph_controller_num_get(devfs_handle_t device)
-{
-	inventory_t *pinv;
-	invplace_t invplace = { NULL, NULL, NULL };
-	int val = -1;
-	if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) {
-		val = (pinv->inv_class == INV_NETWORK)? pinv->inv_unit: pinv->inv_controller;
-	}
-#ifdef DEBUG
-	/*
-	 * It does not make any sense to call this on vertexes with multiple
-	 * inventory structs chained together
-	 */
-	if ( device_inventory_get_next(device, &invplace) != NULL ) {
-		printk("Should panic here ... !\n");
-#endif
-	return (val);	
-}
-
-/*
- * hwgraph_controller_num_set - Sets the controller number in the inventory 
- *	entry.
- */
-void
-hwgraph_controller_num_set(devfs_handle_t device, int contr_num)
-{
-	inventory_t *pinv;
-	invplace_t invplace = { NULL, NULL, NULL };
-	if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) {
-		if (pinv->inv_class == INV_NETWORK)
-			pinv->inv_unit = contr_num;
-		else {
-			if (pinv->inv_class == INV_FCNODE)
-				pinv = device_inventory_get_next(device, &invplace);
-			if (pinv != NULL)
-				pinv->inv_controller = contr_num;
-		}
-	}
-#ifdef DEBUG
-	/*
-	 * It does not make any sense to call this on vertexes with multiple
-	 * inventory structs chained together
-	 */
-	if(pinv != NULL)
-		ASSERT(device_inventory_get_next(device, &invplace) == NULL);
-#endif
-}
-
-/*
- * Find the canonical name for a given vertex by walking back through
- * connectpt's until we hit the hwgraph root vertex (or until we run
- * out of buffer space or until something goes wrong).
- *
- *	COMPATIBILITY FUNCTIONALITY
- * Walks back through 'parents', not necessarily the same as connectpts.
- *
- * Need to resolve the fact that devfs does not return the path from 
- * "/" but rather it just stops right before /dev ..
- */
-int
-hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen)
-{
-	char *locbuf;
-	int   pos;
-
-	if (buflen < 1)
-		return(-1);	/* XXX should be GRAPH_BAD_PARAM ? */
-
-	locbuf = kmalloc(buflen, GFP_KERNEL);
-
-	pos = devfs_generate_path(vhdl, locbuf, buflen);
-	if (pos < 0) {
-		kfree(locbuf);
-		return pos;
-	}
-
-	strcpy(buf, &locbuf[pos]);
-	kfree(locbuf);
-	return 0;
-}
-
-/*
-** vertex_to_name converts a vertex into a canonical name by walking
-** back through connect points until we hit the hwgraph root (or until
-** we run out of buffer space).
-**
-** Usually returns a pointer to the original buffer, filled in as
-** appropriate.  If the buffer is too small to hold the entire name,
-** or if anything goes wrong while determining the name, vertex_to_name
-** returns "UnknownDevice".
-*/
-
-#define DEVNAME_UNKNOWN "UnknownDevice"
-
-char *
-vertex_to_name(devfs_handle_t vhdl, char *buf, uint buflen)
-{
-	if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS)
-		return(buf);
-	else
-		return(DEVNAME_UNKNOWN);
-}
-
-#ifdef LATER
-/*
-** Return the compact node id of the node that ultimately "owns" the specified
-** vertex.  In order to do this, we walk back through masters and connect points
-** until we reach a vertex that represents a node.
-*/
-cnodeid_t
-master_node_get(devfs_handle_t vhdl)
-{
-	cnodeid_t cnodeid;
-	devfs_handle_t master;
-
-	for (;;) {
-		cnodeid = nodevertex_to_cnodeid(vhdl);
-		if (cnodeid != CNODEID_NONE)
-			return(cnodeid);
-
-		master = device_master_get(vhdl);
-
-		/* Check for exceptional cases */
-		if (master == vhdl) {
-			/* Since we got a reference to the "master" thru
-			 * device_master_get() we should decrement
-			 * its reference count by 1
-			 */
-			hwgraph_vertex_unref(master);
-			return(CNODEID_NONE);
-		}
-
-		if (master == GRAPH_VERTEX_NONE) {
-			master = hwgraph_connectpt_get(vhdl);
-			if ((master == GRAPH_VERTEX_NONE) ||
-			    (master == vhdl)) {
-				if (master == vhdl)
-					/* Since we got a reference to the
-					 * "master" thru
-					 * hwgraph_connectpt_get() we should
-					 * decrement its reference count by 1
-					 */
-					hwgraph_vertex_unref(master);
-				return(CNODEID_NONE);
-			}
-		}
-		
-		vhdl = master;
-		/* Decrement the reference to "master" which was got
-		 * either thru device_master_get() or hwgraph_connectpt_get()
-		 * above.
-		 */
-		hwgraph_vertex_unref(master);
-	}
-}
-
-/*
- * Using the canonical path name to get hold of the desired vertex handle will
- * not work on multi-hub sn0 nodes. Hence, we use the following (slightly
- * convoluted) algorithm.
- *
- * - Start at the vertex corresponding to the driver (provided as input parameter)
- * - Loop till you reach a vertex which has EDGE_LBL_MEMORY
- *    - If EDGE_LBL_CONN exists, follow that up.
- *      else if EDGE_LBL_MASTER exists, follow that up.
- *      else follow EDGE_LBL_DOTDOT up.
- *
- * * We should be at desired hub/heart vertex now *
- * - Follow EDGE_LBL_CONN to the widget vertex.
- *
- * - return vertex handle of this widget.
- */
-devfs_handle_t
-mem_vhdl_get(devfs_handle_t drv_vhdl)
-{
-devfs_handle_t cur_vhdl, cur_upper_vhdl;
-devfs_handle_t tmp_mem_vhdl, mem_vhdl;
-graph_error_t loop_rv;
-
-  /* Initializations */
-  cur_vhdl = drv_vhdl;
-  loop_rv = ~GRAPH_SUCCESS;
-
-  /* Loop till current vertex has EDGE_LBL_MEMORY */
-  while (loop_rv != GRAPH_SUCCESS) {
-
-    if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &cur_upper_vhdl)) == GRAPH_SUCCESS) {
-
-    } else if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_MASTER, &cur_upper_vhdl)) == GRAPH_SUCCESS) {
-      } else { /* Follow HWGRAPH_EDGELBL_DOTDOT up */
-           (void) hwgraph_edge_get(cur_vhdl, HWGRAPH_EDGELBL_DOTDOT, &cur_upper_vhdl);
-        }
-
-    cur_vhdl = cur_upper_vhdl;
-
-#if DEBUG && HWG_DEBUG
-    printf("Current vhdl %d \n", cur_vhdl);
-#endif /* DEBUG */
-
-    loop_rv = hwgraph_edge_get(cur_vhdl, EDGE_LBL_MEMORY, &tmp_mem_vhdl);
-  }
-
-  /* We should be at desired hub/heart vertex now */
-  if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &mem_vhdl)) != GRAPH_SUCCESS)
-    return (GRAPH_VERTEX_NONE);
-
-  return (mem_vhdl);
-}
-#endif /* LATER */
-
-
-/*
-** Add a char device -- if the driver supports it -- at a specified vertex.
-*/
-graph_error_t
-hwgraph_char_device_add(        devfs_handle_t from,
-                                char *path,
-                                char *prefix,
-                                devfs_handle_t *devhdl)
-{
-	devfs_handle_t xx = NULL;
-
-	printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n");
-	*devhdl = xx;	// Must set devhdl
-	return(GRAPH_SUCCESS);
-}
-
-graph_error_t
-hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr)
-{
-	printk("WARNING: hwgraph_edge_remove NOT supported.\n");
-	return(GRAPH_ILLEGAL_REQUEST);
-}
-
-graph_error_t
-hwgraph_vertex_unref(devfs_handle_t vhdl)
-{
-	return(GRAPH_ILLEGAL_REQUEST);
-}
-
-
-EXPORT_SYMBOL(hwgraph_mk_dir);
-EXPORT_SYMBOL(hwgraph_path_add);
-EXPORT_SYMBOL(hwgraph_char_device_add);
-EXPORT_SYMBOL(hwgraph_register);
-EXPORT_SYMBOL(hwgraph_vertex_destroy);
-
-EXPORT_SYMBOL(hwgraph_fastinfo_get);
-EXPORT_SYMBOL(hwgraph_edge_get);
-
-EXPORT_SYMBOL(hwgraph_fastinfo_set);
-EXPORT_SYMBOL(hwgraph_connectpt_set);
-EXPORT_SYMBOL(hwgraph_connectpt_get);
-EXPORT_SYMBOL(hwgraph_edge_get_next);
-EXPORT_SYMBOL(hwgraph_info_add_LBL);
-EXPORT_SYMBOL(hwgraph_info_remove_LBL);
-EXPORT_SYMBOL(hwgraph_info_replace_LBL);
-EXPORT_SYMBOL(hwgraph_info_get_LBL);
-EXPORT_SYMBOL(hwgraph_info_get_exported_LBL);
-EXPORT_SYMBOL(hwgraph_info_get_next_LBL);
-EXPORT_SYMBOL(hwgraph_info_export_LBL);
-EXPORT_SYMBOL(hwgraph_info_unexport_LBL);
-EXPORT_SYMBOL(hwgraph_path_lookup);
-EXPORT_SYMBOL(hwgraph_traverse);
-EXPORT_SYMBOL(hwgraph_path_to_vertex);
-EXPORT_SYMBOL(hwgraph_path_to_dev);
-EXPORT_SYMBOL(hwgraph_block_device_get);
-EXPORT_SYMBOL(hwgraph_char_device_get);
-EXPORT_SYMBOL(hwgraph_vertex_name_get);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)