hcl.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:36k
- /* $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-2001 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%xn", 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%0xn", HCL_NAME, hcl_debug);
- printk ("n%s: boot_options: 0x%0xn", HCL_NAME, boot_options);
- #endif
- /*
- * Create the hwgraph_root on devfs.
- */
- rv = hwgraph_path_add(NULL, "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, "linux/busnum", &linux_busnum);
- if (linux_busnum == NULL) {
- panic("HCL: Unable to create hw/linux/busnumn");
- 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 != ' ') && !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 %ldn", (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%pn",
- (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);