2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * hcl - SGI's Hardware Graph compatibility layer.
8 * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved.
11 #include <linux/types.h>
12 #include <linux/config.h>
13 #include <linux/slab.h>
14 #include <linux/ctype.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/sched.h> /* needed for smp_lock.h :( */
21 #include <linux/smp_lock.h>
22 #include <asm/sn/sgi.h>
24 #include <asm/sn/iograph.h>
25 #include <asm/sn/hwgfs.h>
26 #include <asm/sn/invent.h>
27 #include <asm/sn/hcl.h>
28 #include <asm/sn/labelcl.h>
29 #include <asm/sn/simulator.h>
31 #define vertex_hdl_t hwgfs_handle_t
33 vertex_hdl_t hwgraph_root;
34 vertex_hdl_t linux_busnum;
35 extern void pci_bus_cvlink_init(void);
36 unsigned long hwgraph_debug_mask = 0;
39 * Debug flag definition.
41 #define OPTION_NONE 0x00
42 #define HCL_DEBUG_NONE 0x00000
43 #define HCL_DEBUG_ALL 0x0ffff
44 #if defined(CONFIG_HCL_DEBUG)
45 static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE;
47 static unsigned int hcl_debug = HCL_DEBUG_NONE;
48 #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
49 static unsigned int boot_options = OPTION_NONE;
53 * Some Global definitions.
55 vertex_hdl_t hcl_handle;
57 invplace_t invplace_none = {
59 GRAPH_VERTEX_PLACE_NONE,
65 * The purpose of this device driver is to provide a facility
66 * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path
67 * to manipulate label entries without having to implement
68 * system call interfaces. This methodology will enable us to
69 * make this feature module loadable.
71 static int hcl_open(struct inode * inode, struct file * filp)
74 printk("HCL: hcl_open called.\n");
81 static int hcl_close(struct inode * inode, struct file * filp)
85 printk("HCL: hcl_close called.\n");
92 static int hcl_ioctl(struct inode * inode, struct file * file,
93 unsigned int cmd, unsigned long arg)
97 printk("HCL: hcl_ioctl called.\n");
103 printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd);
111 struct file_operations hcl_fops = {
113 NULL, /* lseek - default */
114 NULL, /* read - general block-dev read */
115 NULL, /* write - general block-dev write */
116 NULL, /* readdir - bad */
118 hcl_ioctl, /* ioctl */
122 hcl_close, /* release */
132 * init_hcl() - Boot time initialization.
135 int __init init_hcl(void)
137 extern void string_table_init(struct string_table *);
138 extern struct string_table label_string_table;
139 extern int init_ifconfig_net(void);
140 extern int init_ioconfig_bus(void);
141 extern int init_hwgfs_fs(void);
144 if (IS_RUNNING_ON_SIMULATOR()) {
145 extern u64 klgraph_addr[];
146 klgraph_addr[0] = 0xe000003000030000;
152 * Create the hwgraph_root.
154 rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root);
156 panic("init_hcl: Failed to create hwgraph_root.\n");
159 * Create the hcl driver to support inventory entry manipulations.
162 hcl_handle = hwgraph_register(hwgraph_root, ".hcl",
163 0, DEVFS_FL_AUTO_DEVNUM,
165 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
168 if (hcl_handle == NULL) {
169 panic("HCL: Unable to create HCL Driver in init_hcl().\n");
174 * Initialize the HCL string table.
177 string_table_init(&label_string_table);
180 * Create the directory that links Linux bus numbers to our Xwidget.
182 rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum);
183 if (linux_busnum == NULL) {
184 panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS);
188 pci_bus_cvlink_init();
191 * Initialize the ifconfgi_net driver that does network devices
203 * hcl_setup() - Process boot time parameters if given.
205 * This routine gets called only if "hcl=" is given in the
206 * boot line and before init_hcl().
208 * We currently do not have any boot options .. when we do,
209 * functionalities can be added here.
212 static int __init hcl_setup(char *str)
214 while ( (*str != '\0') && !isspace (*str) )
216 #ifdef CONFIG_HCL_DEBUG
217 if (strncmp (str, "all", 3) == 0) {
218 hcl_debug_init |= HCL_DEBUG_ALL;
223 if (*str != ',') return 0;
231 __setup("hcl=", hcl_setup);
235 hwgraph_generate_path(
240 return (hwgfs_generate_path(de, path, buflen));
244 * Set device specific "fast information".
248 hwgraph_fastinfo_set(vertex_hdl_t de, arbitrary_info_t fastinfo)
250 labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL);
255 * Get device specific "fast information".
259 hwgraph_fastinfo_get(vertex_hdl_t de)
261 arbitrary_info_t fastinfo;
265 printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n");
269 rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo);
278 * hwgraph_connectpt_set - Sets the connect point handle in de to the
279 * given connect_de handle. By default, the connect point of the
280 * node is the parent. This effectively changes this assumption.
283 hwgraph_connectpt_set(vertex_hdl_t de, vertex_hdl_t connect_de)
290 rv = labelcl_info_connectpt_set(de, connect_de);
297 * hwgraph_connectpt_get: Returns the entry's connect point.
301 hwgraph_connectpt_get(vertex_hdl_t de)
304 arbitrary_info_t info;
305 vertex_hdl_t connect;
307 rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
312 connect = (vertex_hdl_t)info;
319 * hwgraph_mk_dir - Creates a directory entry.
322 hwgraph_mk_dir(vertex_hdl_t de, const char *name,
323 unsigned int namelen, void *info)
327 labelcl_info_t *labelcl_info = NULL;
328 vertex_hdl_t new_handle = NULL;
329 vertex_hdl_t parent = NULL;
332 * Create the device info structure for hwgraph compatiblity support.
334 labelcl_info = labelcl_info_create();
341 new_handle = hwgfs_mk_dir(de, name, (void *)labelcl_info);
343 labelcl_info_destroy(labelcl_info);
348 * Get the parent handle.
350 parent = hwgfs_get_parent (new_handle);
353 * To provide the same semantics as the hwgraph, set the connect point.
355 rv = hwgraph_connectpt_set(new_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_handle, (arbitrary_info_t)info);
375 * hwgraph_path_add - Create a directory node with the given path starting
376 * from the given fromv.
379 hwgraph_path_add(vertex_hdl_t fromv,
381 vertex_hdl_t *new_de)
384 unsigned int namelen = strlen(path);
388 * We need to handle the case when fromv is NULL ..
389 * in this case we need to create the path from the
393 fromv = hwgraph_root;
396 * check the entry doesn't already exist, if it does
397 * then we simply want new_de to point to it (otherwise
398 * we'll overwrite the existing labelcl_info struct)
400 rv = hwgraph_edge_get(fromv, path, new_de);
401 if (rv) { /* couldn't find entry so we create it */
402 *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL);
414 * hwgraph_register - Creates a special device file.
418 hwgraph_register(vertex_hdl_t de, const char *name,
419 unsigned int namelen, unsigned int flags,
420 unsigned int major, unsigned int minor,
421 umode_t mode, uid_t uid, gid_t gid,
422 struct file_operations *fops,
426 vertex_hdl_t new_handle = NULL;
431 new_handle = hwgfs_register(de, name, flags, major,
432 minor, mode, fops, info);
440 * hwgraph_mk_symlink - Create a symbolic link.
443 hwgraph_mk_symlink(vertex_hdl_t de, const char *name, unsigned int namelen,
444 unsigned int flags, const char *link, unsigned int linklen,
445 vertex_hdl_t *handle, void *info)
448 void *labelcl_info = NULL;
450 vertex_hdl_t new_handle = NULL;
453 * Create the labelcl info structure for hwgraph compatiblity support.
455 labelcl_info = labelcl_info_create();
460 * Create a symbolic link.
462 status = hwgfs_mk_symlink(de, name, flags, link,
463 &new_handle, labelcl_info);
464 if ( (!new_handle) || (!status) ){
465 labelcl_info_destroy((labelcl_info_t *)labelcl_info);
470 * If the caller provides a private data pointer, save it in the
471 * labelcl info structure(fastinfo). This can be retrieved via
472 * hwgraph_fastinfo_get()
475 hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info);
477 *handle = new_handle;
483 * hwgraph_vertex_destroy - Destroy the entry
486 hwgraph_vertex_destroy(vertex_hdl_t de)
489 void *labelcl_info = NULL;
491 labelcl_info = hwgfs_get_info(de);
492 hwgfs_unregister(de);
495 labelcl_info_destroy((labelcl_info_t *)labelcl_info);
501 hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name)
507 vertex_hdl_t handle = NULL;
511 path = kmalloc(1024, GFP_KERNEL);
512 memset((char *)path, 0x0, 1024);
513 link = kmalloc(1024, GFP_KERNEL);
514 memset((char *)link, 0x0, 1024);
516 i = hwgfs_generate_path (from, path, 1024);
520 index = strstr (s1, "/");
530 for (i = 0; i < count; i++) {
531 strcat((char *)link,"../");
534 memset(path, 0x0, 1024);
535 i = hwgfs_generate_path (to, path, 1024);
536 strcat((char *)link, (char *)path);
539 * Otherwise, just create a symlink to the vertex.
540 * In this case the vertex was previous created with a REAL pathname.
542 rv = hwgfs_mk_symlink (from, (const char *)name,
543 DEVFS_FL_DEFAULT, link,
555 hwgraph_edge_get(vertex_hdl_t from, char *name, vertex_hdl_t *toptr)
558 vertex_hdl_t target_handle = NULL;
567 * If the name is "." just return the current entry handle.
569 if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) {
573 } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) {
575 * Hmmm .. should we return the connect point or parent ..
576 * see in hwgraph, the concept of parent is the connectpt!
578 * Maybe we should see whether the connectpt is set .. if
579 * not just return the parent!
581 target_handle = hwgraph_connectpt_get(from);
584 * Just return the connect point.
586 *toptr = target_handle;
589 target_handle = hwgfs_get_parent(from);
590 *toptr = target_handle;
593 target_handle = hwgfs_find_handle (from, name, 0, 0,
594 0, 1); /* Yes traverse symbolic links */
597 if (target_handle == NULL)
600 *toptr = target_handle;
606 * hwgraph_info_add_LBL - Adds a new label for the device. Mark the info_desc
607 * of the label as INFO_DESC_PRIVATE and store the info in the label.
611 hwgraph_info_add_LBL( vertex_hdl_t de,
613 arbitrary_info_t info)
615 return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info));
619 * hwgraph_info_remove_LBL - Remove the label entry for the device.
623 hwgraph_info_remove_LBL( vertex_hdl_t de,
625 arbitrary_info_t *old_info)
627 return(labelcl_info_remove_LBL(de, name, NULL, old_info));
631 * hwgraph_info_replace_LBL - replaces an existing label with
632 * a new label info value.
636 hwgraph_info_replace_LBL( vertex_hdl_t de,
638 arbitrary_info_t info,
639 arbitrary_info_t *old_info)
641 return(labelcl_info_replace_LBL(de, name,
642 INFO_DESC_PRIVATE, info,
646 * hwgraph_info_get_LBL - Get and return the info value in the label of the
651 hwgraph_info_get_LBL(vertex_hdl_t de,
653 arbitrary_info_t *infop)
655 return(labelcl_info_get_LBL(de, name, NULL, infop));
659 * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer
660 * of the given label for the device. The weird thing is that the label
661 * that matches the name is return irrespective of the info_desc value!
662 * Do not understand why the word "exported" is used!
666 hwgraph_info_get_exported_LBL(vertex_hdl_t de,
669 arbitrary_info_t *infop)
672 arb_info_desc_t info_desc;
674 rc = labelcl_info_get_LBL(de, name, &info_desc, infop);
676 *export_info = (int)info_desc;
682 * hwgraph_info_get_next_LBL - Returns the next label info given the
683 * current label entry in place.
685 * Once again this has no locking or reference count for protection.
690 hwgraph_info_get_next_LBL(vertex_hdl_t de,
692 arbitrary_info_t *infop,
693 labelcl_info_place_t *place)
695 return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place));
699 * hwgraph_info_export_LBL - Retrieve the specified label entry and modify
700 * the info_desc field with the given value in nbytes.
704 hwgraph_info_export_LBL(vertex_hdl_t de, char *name, int nbytes)
706 arbitrary_info_t info;
710 nbytes = INFO_DESC_EXPORT;
715 rc = labelcl_info_get_LBL(de, name, NULL, &info);
719 rc = labelcl_info_replace_LBL(de, name,
720 nbytes, info, NULL, NULL);
726 * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the
727 * label info_descr filed to INFO_DESC_PRIVATE.
731 hwgraph_info_unexport_LBL(vertex_hdl_t de, char *name)
733 arbitrary_info_t info;
736 rc = labelcl_info_get_LBL(de, name, NULL, &info);
740 rc = labelcl_info_replace_LBL(de, name,
741 INFO_DESC_PRIVATE, info, NULL, NULL);
747 * hwgraph_path_lookup - return the handle for the given path.
751 hwgraph_path_lookup(vertex_hdl_t start_vertex_handle,
753 vertex_hdl_t *vertex_handle_ptr,
756 *vertex_handle_ptr = hwgfs_find_handle(start_vertex_handle, /* start dir */
757 lookup_path, /* path */
760 0, /* char | block */
761 1); /* traverse symlinks */
762 if (*vertex_handle_ptr == NULL)
769 * hwgraph_traverse - Find and return the handle starting from de.
773 hwgraph_traverse(vertex_hdl_t de, char *path, vertex_hdl_t *found)
776 * get the directory entry (path should end in a directory)
779 *found = hwgfs_find_handle(de, /* start dir */
783 0, /* char | block */
784 1); /* traverse symlinks */
786 return(GRAPH_NOT_FOUND);
788 return(GRAPH_SUCCESS);
792 * hwgraph_path_to_vertex - Return the entry handle for the given
793 * pathname .. assume traverse symlinks too!.
796 hwgraph_path_to_vertex(char *path)
798 return(hwgfs_find_handle(NULL, /* start dir */
802 0, /* char | block */
803 1)); /* traverse symlinks */
807 * hwgraph_inventory_remove - Removes an inventory entry.
809 * Remove an inventory item associated with a vertex. It is the caller's
810 * responsibility to make sure that there are no races between removing
811 * inventory from a vertex and simultaneously removing that vertex.
814 hwgraph_inventory_remove( vertex_hdl_t de,
821 return(0); /* Just a Stub for IRIX code. */
825 * Find the canonical name for a given vertex by walking back through
826 * connectpt's until we hit the hwgraph root vertex (or until we run
827 * out of buffer space or until something goes wrong).
829 * COMPATIBILITY FUNCTIONALITY
830 * Walks back through 'parents', not necessarily the same as connectpts.
832 * Need to resolve the fact that does not return the path from
833 * "/" but rather it just stops right before /dev ..
836 hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen)
842 return(-1); /* XXX should be GRAPH_BAD_PARAM ? */
844 locbuf = kmalloc(buflen, GFP_KERNEL);
846 pos = hwgfs_generate_path(vhdl, locbuf, buflen);
852 strcpy(buf, &locbuf[pos]);
858 ** vertex_to_name converts a vertex into a canonical name by walking
859 ** back through connect points until we hit the hwgraph root (or until
860 ** we run out of buffer space).
862 ** Usually returns a pointer to the original buffer, filled in as
863 ** appropriate. If the buffer is too small to hold the entire name,
864 ** or if anything goes wrong while determining the name, vertex_to_name
865 ** returns "UnknownDevice".
868 #define DEVNAME_UNKNOWN "UnknownDevice"
871 vertex_to_name(vertex_hdl_t vhdl, char *buf, uint buflen)
873 if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS)
876 return(DEVNAME_UNKNOWN);
880 hwgraph_edge_remove(vertex_hdl_t from, char *name, vertex_hdl_t *toptr)
882 return(GRAPH_ILLEGAL_REQUEST);
886 hwgraph_vertex_unref(vertex_hdl_t vhdl)
888 return(GRAPH_ILLEGAL_REQUEST);
892 hwgraph_debug(char *file, char * function, int line, vertex_hdl_t vhdl1, vertex_hdl_t vhdl2, char *format, ...)
899 if ( !hwgraph_debug_mask )
902 hwpath = kmalloc(MAXDEVNAME, GFP_KERNEL);
906 printk("HWGRAPH_DEBUG %s %s %d : ", file, function, line);
909 memset(hwpath, 0, MAXDEVNAME);
910 pos = hwgfs_generate_path(vhdl1, hwpath, MAXDEVNAME);
911 printk("vhdl1 = %s : ", &hwpath[pos]);
915 memset(hwpath, 0, MAXDEVNAME);
916 pos = hwgfs_generate_path(vhdl2, hwpath, MAXDEVNAME);
917 printk("vhdl2 = %s :", &hwpath[pos]);
920 memset(hwpath, 0, MAXDEVNAME);
921 va_start(ap, format);
922 vsnprintf(hwpath, 500, format, ap);
924 hwpath[MAXDEVNAME -1] = (char)0; /* Just in case. */
925 printk(" %s", hwpath);
929 EXPORT_SYMBOL(hwgraph_mk_dir);
930 EXPORT_SYMBOL(hwgraph_path_add);
931 EXPORT_SYMBOL(hwgraph_register);
932 EXPORT_SYMBOL(hwgraph_vertex_destroy);
933 EXPORT_SYMBOL(hwgraph_fastinfo_get);
934 EXPORT_SYMBOL(hwgraph_fastinfo_set);
935 EXPORT_SYMBOL(hwgraph_connectpt_set);
936 EXPORT_SYMBOL(hwgraph_connectpt_get);
937 EXPORT_SYMBOL(hwgraph_info_add_LBL);
938 EXPORT_SYMBOL(hwgraph_info_remove_LBL);
939 EXPORT_SYMBOL(hwgraph_info_replace_LBL);
940 EXPORT_SYMBOL(hwgraph_info_get_LBL);
941 EXPORT_SYMBOL(hwgraph_info_get_exported_LBL);
942 EXPORT_SYMBOL(hwgraph_info_get_next_LBL);
943 EXPORT_SYMBOL(hwgraph_info_export_LBL);
944 EXPORT_SYMBOL(hwgraph_info_unexport_LBL);
945 EXPORT_SYMBOL(hwgraph_path_lookup);
946 EXPORT_SYMBOL(hwgraph_traverse);
947 EXPORT_SYMBOL(hwgraph_vertex_name_get);