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