import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / ia64 / sn / io / hwgfs / hcl.c
1 /*
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
4  * for more details.
5  *
6  *  hcl - SGI's Hardware Graph compatibility layer.
7  *
8  * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved.
9  */
10
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>
18 #include <linux/fs.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>
23 #include <asm/io.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>
30
31 #define vertex_hdl_t hwgfs_handle_t
32
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;
37
38 /*
39  * Debug flag definition.
40  */
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;
46 #endif
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;
50 #endif
51
52 /*
53  * Some Global definitions.
54  */
55 vertex_hdl_t hcl_handle;
56
57 invplace_t invplace_none = {
58         GRAPH_VERTEX_NONE,
59         GRAPH_VERTEX_PLACE_NONE,
60         NULL
61 };
62
63 /*
64  * HCL device driver.
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.
70  */
71 static int hcl_open(struct inode * inode, struct file * filp)
72 {
73         if (hcl_debug) {
74                 printk("HCL: hcl_open called.\n");
75         }
76
77         return(0);
78
79 }
80
81 static int hcl_close(struct inode * inode, struct file * filp)
82 {
83
84         if (hcl_debug) {
85                 printk("HCL: hcl_close called.\n");
86         }
87
88         return(0);
89
90 }
91
92 static int hcl_ioctl(struct inode * inode, struct file * file,
93         unsigned int cmd, unsigned long arg)
94 {
95
96         if (hcl_debug) {
97                 printk("HCL: hcl_ioctl called.\n");
98         }
99
100         switch (cmd) {
101                 default:
102                         if (hcl_debug) {
103                                 printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd);
104                         }
105         }
106
107         return(0);
108
109 }
110
111 struct file_operations hcl_fops = {
112         (struct module *)0,
113         NULL,           /* lseek - default */
114         NULL,           /* read - general block-dev read */
115         NULL,           /* write - general block-dev write */
116         NULL,           /* readdir - bad */
117         NULL,           /* poll */
118         hcl_ioctl,      /* ioctl */
119         NULL,           /* mmap */
120         hcl_open,       /* open */
121         NULL,           /* flush */
122         hcl_close,      /* release */
123         NULL,           /* fsync */
124         NULL,           /* fasync */
125         NULL,           /* lock */
126         NULL,           /* readv */
127         NULL,           /* writev */
128 };
129
130
131 /*
132  * init_hcl() - Boot time initialization.
133  *
134  */
135 int __init init_hcl(void)
136 {
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);
142         int rv = 0;
143
144         if (IS_RUNNING_ON_SIMULATOR()) {
145                 extern u64 klgraph_addr[];
146                 klgraph_addr[0] = 0xe000003000030000;
147         }
148
149         init_hwgfs_fs();
150
151         /*
152          * Create the hwgraph_root.
153          */
154         rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root);
155         if (rv)
156                 panic("init_hcl: Failed to create hwgraph_root.\n");
157
158         /*
159          * Create the hcl driver to support inventory entry manipulations.
160          *
161          */
162         hcl_handle = hwgraph_register(hwgraph_root, ".hcl",
163                         0, DEVFS_FL_AUTO_DEVNUM,
164                         0, 0,
165                         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
166                         &hcl_fops, NULL);
167
168         if (hcl_handle == NULL) {
169                 panic("HCL: Unable to create HCL Driver in init_hcl().\n");
170                 return(0);
171         }
172
173         /*
174          * Initialize the HCL string table.
175          */
176
177         string_table_init(&label_string_table);
178
179         /*
180          * Create the directory that links Linux bus numbers to our Xwidget.
181          */
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);
185                 return(0);
186         }
187
188         pci_bus_cvlink_init();
189
190         /*
191          * Initialize the ifconfgi_net driver that does network devices 
192          * Persistent Naming.
193          */
194         init_ifconfig_net();
195         init_ioconfig_bus();
196
197         return(0);
198
199 }
200
201
202 /*
203  * hcl_setup() - Process boot time parameters if given.
204  *      "hcl="
205  *      This routine gets called only if "hcl=" is given in the 
206  *      boot line and before init_hcl().
207  *
208  *      We currently do not have any boot options .. when we do, 
209  *      functionalities can be added here.
210  *
211  */
212 static int __init hcl_setup(char *str)
213 {
214     while ( (*str != '\0') && !isspace (*str) )
215     {
216 #ifdef CONFIG_HCL_DEBUG
217         if (strncmp (str, "all", 3) == 0) {
218             hcl_debug_init |= HCL_DEBUG_ALL;
219             str += 3;
220         } else 
221                 return 0;
222 #endif
223         if (*str != ',') return 0;
224         ++str;
225     }
226
227     return 1;
228
229 }
230
231 __setup("hcl=", hcl_setup);
232
233
234 int
235 hwgraph_generate_path(
236         vertex_hdl_t            de,
237         char                    *path,
238         int                     buflen)
239 {
240         return (hwgfs_generate_path(de, path, buflen));
241 }
242
243 /*
244  * Set device specific "fast information".
245  *
246  */
247 void
248 hwgraph_fastinfo_set(vertex_hdl_t de, arbitrary_info_t fastinfo)
249 {
250         labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL);
251 }
252
253
254 /*
255  * Get device specific "fast information".
256  *
257  */
258 arbitrary_info_t
259 hwgraph_fastinfo_get(vertex_hdl_t de)
260 {
261         arbitrary_info_t fastinfo;
262         int rv;
263
264         if (!de) {
265                 printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n");
266                 return(-1);
267         }
268
269         rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo);
270         if (rv == 0)
271                 return(fastinfo);
272
273         return(0);
274 }
275
276
277 /*
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.
281  */
282 int
283 hwgraph_connectpt_set(vertex_hdl_t de, vertex_hdl_t connect_de)
284 {
285         int rv;
286
287         if (!de)
288                 return(-1);
289
290         rv = labelcl_info_connectpt_set(de, connect_de);
291
292         return(rv);
293 }
294
295
296 /*
297  * hwgraph_connectpt_get: Returns the entry's connect point.
298  *
299  */
300 vertex_hdl_t
301 hwgraph_connectpt_get(vertex_hdl_t de)
302 {
303         int rv;
304         arbitrary_info_t info;
305         vertex_hdl_t connect;
306
307         rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
308         if (rv != 0) {
309                 return(NULL);
310         }
311
312         connect = (vertex_hdl_t)info;
313         return(connect);
314
315 }
316
317
318 /*
319  * hwgraph_mk_dir - Creates a directory entry.
320  */
321 vertex_hdl_t
322 hwgraph_mk_dir(vertex_hdl_t de, const char *name,
323                 unsigned int namelen, void *info)
324 {
325
326         int rv;
327         labelcl_info_t *labelcl_info = NULL;
328         vertex_hdl_t new_handle = NULL;
329         vertex_hdl_t parent = NULL;
330
331         /*
332          * Create the device info structure for hwgraph compatiblity support.
333          */
334         labelcl_info = labelcl_info_create();
335         if (!labelcl_info)
336                 return(NULL);
337
338         /*
339          * Create an entry.
340          */
341         new_handle = hwgfs_mk_dir(de, name, (void *)labelcl_info);
342         if (!new_handle) {
343                 labelcl_info_destroy(labelcl_info);
344                 return(NULL);
345         }
346
347         /*
348          * Get the parent handle.
349          */
350         parent = hwgfs_get_parent (new_handle);
351
352         /*
353          * To provide the same semantics as the hwgraph, set the connect point.
354          */
355         rv = hwgraph_connectpt_set(new_handle, parent);
356         if (!rv) {
357                 /*
358                  * We need to clean up!
359                  */
360         }
361
362         /*
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()
366          */
367         if (info)
368                 hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info);
369                 
370         return(new_handle);
371
372 }
373
374 /*
375  * hwgraph_path_add - Create a directory node with the given path starting 
376  * from the given fromv.
377  */
378 int
379 hwgraph_path_add(vertex_hdl_t  fromv,
380                  char *path,
381                  vertex_hdl_t *new_de)
382 {
383
384         unsigned int    namelen = strlen(path);
385         int             rv;
386
387         /*
388          * We need to handle the case when fromv is NULL ..
389          * in this case we need to create the path from the 
390          * hwgraph root!
391          */
392         if (fromv == NULL)
393                 fromv = hwgraph_root;
394
395         /*
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)
399          */
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);
403                 if (new_de == NULL)
404                         return(-1);
405                 else
406                         return(0);
407         }
408         else 
409                 return(0);
410
411 }
412
413 /*
414  * hwgraph_register  - Creates a special device file.
415  *
416  */
417 vertex_hdl_t
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,
423                 void *info)
424 {
425
426         vertex_hdl_t new_handle = NULL;
427
428         /*
429          * Create an entry.
430          */
431         new_handle = hwgfs_register(de, name, flags, major,
432                                 minor, mode, fops, info);
433
434         return(new_handle);
435
436 }
437
438
439 /*
440  * hwgraph_mk_symlink - Create a symbolic link.
441  */
442 int
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)
446 {
447
448         void *labelcl_info = NULL;
449         int status = 0;
450         vertex_hdl_t new_handle = NULL;
451
452         /*
453          * Create the labelcl info structure for hwgraph compatiblity support.
454          */
455         labelcl_info = labelcl_info_create();
456         if (!labelcl_info)
457                 return(-1);
458
459         /*
460          * Create a symbolic link.
461          */
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);
466                 return(-1);
467         }
468
469         /*
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()
473          */
474         if (info)
475                 hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info);
476
477         *handle = new_handle;
478         return(0);
479
480 }
481
482 /*
483  * hwgraph_vertex_destroy - Destroy the entry
484  */
485 int
486 hwgraph_vertex_destroy(vertex_hdl_t de)
487 {
488
489         void *labelcl_info = NULL;
490
491         labelcl_info = hwgfs_get_info(de);
492         hwgfs_unregister(de);
493
494         if (labelcl_info)
495                 labelcl_info_destroy((labelcl_info_t *)labelcl_info);
496
497         return(0);
498 }
499
500 int
501 hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name)
502 {
503
504         char *path, *link;
505         char *s1;
506         char *index;
507         vertex_hdl_t handle = NULL;
508         int rv;
509         int i, count;
510
511         path = kmalloc(1024, GFP_KERNEL);
512         memset((char *)path, 0x0, 1024);
513         link = kmalloc(1024, GFP_KERNEL);
514         memset((char *)link, 0x0, 1024);
515
516         i = hwgfs_generate_path (from, path, 1024);
517         s1 = (char *)path;
518         count = 0;
519         while (1) {
520                 index = strstr (s1, "/");
521                 if (index) {
522                         count++;
523                         s1 = ++index;
524                 } else {
525                         count++;
526                         break;
527                 }
528         }
529
530         for (i = 0; i < count; i++) {
531                 strcat((char *)link,"../");
532         }
533
534         memset(path, 0x0, 1024);
535         i = hwgfs_generate_path (to, path, 1024);
536         strcat((char *)link, (char *)path);
537
538         /*
539          * Otherwise, just create a symlink to the vertex.
540          * In this case the vertex was previous created with a REAL pathname.
541          */
542         rv = hwgfs_mk_symlink (from, (const char *)name,
543                                DEVFS_FL_DEFAULT, link,
544                                &handle, NULL);
545         kfree(path);
546         kfree(link);
547
548         return(rv);
549
550
551 }
552
553 /* ARGSUSED */
554 int
555 hwgraph_edge_get(vertex_hdl_t from, char *name, vertex_hdl_t *toptr)
556 {
557
558         vertex_hdl_t target_handle = NULL;
559
560         if (name == NULL)
561                 return(-1);
562
563         if (toptr == NULL)
564                 return(-1);
565
566         /*
567          * If the name is "." just return the current entry handle.
568          */
569         if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) {
570                 if (toptr) {
571                         *toptr = from;
572                 }
573         } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) {
574                 /*
575                  * Hmmm .. should we return the connect point or parent ..
576                  * see in hwgraph, the concept of parent is the connectpt!
577                  *
578                  * Maybe we should see whether the connectpt is set .. if 
579                  * not just return the parent!
580                  */
581                 target_handle = hwgraph_connectpt_get(from);
582                 if (target_handle) {
583                         /*
584                          * Just return the connect point.
585                          */
586                         *toptr = target_handle;
587                         return(0);
588                 }
589                 target_handle = hwgfs_get_parent(from);
590                 *toptr = target_handle;
591
592         } else {
593                 target_handle = hwgfs_find_handle (from, name, 0, 0,
594                                         0, 1); /* Yes traverse symbolic links */
595         }
596
597         if (target_handle == NULL)
598                 return(-1);
599         else
600          *toptr = target_handle;
601
602         return(0);
603 }
604
605 /*
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.
608  */
609 /* ARGSUSED */
610 int
611 hwgraph_info_add_LBL( vertex_hdl_t de,
612                         char *name,
613                         arbitrary_info_t info)
614 {
615         return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info));
616 }
617
618 /*
619  * hwgraph_info_remove_LBL - Remove the label entry for the device.
620  */
621 /* ARGSUSED */
622 int
623 hwgraph_info_remove_LBL( vertex_hdl_t de,
624                                 char *name,
625                                 arbitrary_info_t *old_info)
626 {
627         return(labelcl_info_remove_LBL(de, name, NULL, old_info));
628 }
629
630 /*
631  * hwgraph_info_replace_LBL - replaces an existing label with 
632  *      a new label info value.
633  */
634 /* ARGSUSED */
635 int
636 hwgraph_info_replace_LBL( vertex_hdl_t de,
637                                 char *name,
638                                 arbitrary_info_t info,
639                                 arbitrary_info_t *old_info)
640 {
641         return(labelcl_info_replace_LBL(de, name,
642                         INFO_DESC_PRIVATE, info,
643                         NULL, old_info));
644 }
645 /*
646  * hwgraph_info_get_LBL - Get and return the info value in the label of the 
647  *      device.
648  */
649 /* ARGSUSED */
650 int
651 hwgraph_info_get_LBL(vertex_hdl_t de,
652                         char *name,
653                         arbitrary_info_t *infop)
654 {
655         return(labelcl_info_get_LBL(de, name, NULL, infop));
656 }
657
658 /*
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!
663  */
664 /* ARGSUSED */
665 int
666 hwgraph_info_get_exported_LBL(vertex_hdl_t de,
667                                 char *name,
668                                 int *export_info,
669                                 arbitrary_info_t *infop)
670 {
671         int rc;
672         arb_info_desc_t info_desc;
673
674         rc = labelcl_info_get_LBL(de, name, &info_desc, infop);
675         if (rc == 0)
676                 *export_info = (int)info_desc;
677
678         return(rc);
679 }
680
681 /*
682  * hwgraph_info_get_next_LBL - Returns the next label info given the 
683  *      current label entry in place.
684  *
685  *      Once again this has no locking or reference count for protection.
686  *
687  */
688 /* ARGSUSED */
689 int
690 hwgraph_info_get_next_LBL(vertex_hdl_t de,
691                                 char *buf,
692                                 arbitrary_info_t *infop,
693                                 labelcl_info_place_t *place)
694 {
695         return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place));
696 }
697
698 /*
699  * hwgraph_info_export_LBL - Retrieve the specified label entry and modify 
700  *      the info_desc field with the given value in nbytes.
701  */
702 /* ARGSUSED */
703 int
704 hwgraph_info_export_LBL(vertex_hdl_t de, char *name, int nbytes)
705 {
706         arbitrary_info_t info;
707         int rc;
708
709         if (nbytes == 0)
710                 nbytes = INFO_DESC_EXPORT;
711
712         if (nbytes < 0)
713                 return(-1);
714
715         rc = labelcl_info_get_LBL(de, name, NULL, &info);
716         if (rc != 0)
717                 return(rc);
718
719         rc = labelcl_info_replace_LBL(de, name,
720                                 nbytes, info, NULL, NULL);
721
722         return(rc);
723 }
724
725 /*
726  * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the 
727  * label info_descr filed to INFO_DESC_PRIVATE.
728  */
729 /* ARGSUSED */
730 int
731 hwgraph_info_unexport_LBL(vertex_hdl_t de, char *name)
732 {
733         arbitrary_info_t info;
734         int rc;
735
736         rc = labelcl_info_get_LBL(de, name, NULL, &info);
737         if (rc != 0)
738                 return(rc);
739
740         rc = labelcl_info_replace_LBL(de, name,
741                                 INFO_DESC_PRIVATE, info, NULL, NULL);
742
743         return(rc);
744 }
745
746 /*
747  * hwgraph_path_lookup - return the handle for the given path.
748  *
749  */
750 int
751 hwgraph_path_lookup(vertex_hdl_t start_vertex_handle,
752                         char *lookup_path,
753                         vertex_hdl_t *vertex_handle_ptr,
754                         char **remainder)
755 {
756         *vertex_handle_ptr = hwgfs_find_handle(start_vertex_handle,     /* start dir */
757                                         lookup_path,            /* path */
758                                         0,                      /* major */
759                                         0,                      /* minor */
760                                         0,                      /* char | block */
761                                         1);                     /* traverse symlinks */
762         if (*vertex_handle_ptr == NULL)
763                 return(-1);
764         else
765                 return(0);
766 }
767
768 /*
769  * hwgraph_traverse - Find and return the handle starting from de.
770  *
771  */
772 graph_error_t
773 hwgraph_traverse(vertex_hdl_t de, char *path, vertex_hdl_t *found)
774 {
775         /* 
776          * get the directory entry (path should end in a directory)
777          */
778
779         *found = hwgfs_find_handle(de,  /* start dir */
780                             path,       /* path */
781                             0,          /* major */
782                             0,          /* minor */
783                             0,          /* char | block */
784                             1);         /* traverse symlinks */
785         if (*found == NULL)
786                 return(GRAPH_NOT_FOUND);
787         else
788                 return(GRAPH_SUCCESS);
789 }
790
791 /*
792  * hwgraph_path_to_vertex - Return the entry handle for the given 
793  *      pathname .. assume traverse symlinks too!.
794  */
795 vertex_hdl_t
796 hwgraph_path_to_vertex(char *path)
797 {
798         return(hwgfs_find_handle(NULL,  /* start dir */
799                         path,           /* path */
800                         0,              /* major */
801                         0,              /* minor */
802                         0,              /* char | block */
803                         1));            /* traverse symlinks */
804 }
805
806 /*
807  * hwgraph_inventory_remove - Removes an inventory entry.
808  *
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.
812 */
813 int
814 hwgraph_inventory_remove(       vertex_hdl_t de,
815                                 int class,
816                                 int type,
817                                 major_t controller,
818                                 minor_t unit,
819                                 int state)
820 {
821         return(0); /* Just a Stub for IRIX code. */
822 }
823
824 /*
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).
828  *
829  *      COMPATIBILITY FUNCTIONALITY
830  * Walks back through 'parents', not necessarily the same as connectpts.
831  *
832  * Need to resolve the fact that does not return the path from 
833  * "/" but rather it just stops right before /dev ..
834  */
835 int
836 hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen)
837 {
838         char *locbuf;
839         int   pos;
840
841         if (buflen < 1)
842                 return(-1);     /* XXX should be GRAPH_BAD_PARAM ? */
843
844         locbuf = kmalloc(buflen, GFP_KERNEL);
845
846         pos = hwgfs_generate_path(vhdl, locbuf, buflen);
847         if (pos < 0) {
848                 kfree(locbuf);
849                 return pos;
850         }
851
852         strcpy(buf, &locbuf[pos]);
853         kfree(locbuf);
854         return 0;
855 }
856
857 /*
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).
861 **
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".
866 */
867
868 #define DEVNAME_UNKNOWN "UnknownDevice"
869
870 char *
871 vertex_to_name(vertex_hdl_t vhdl, char *buf, uint buflen)
872 {
873         if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS)
874                 return(buf);
875         else
876                 return(DEVNAME_UNKNOWN);
877 }
878
879 graph_error_t
880 hwgraph_edge_remove(vertex_hdl_t from, char *name, vertex_hdl_t *toptr)
881 {
882         return(GRAPH_ILLEGAL_REQUEST);
883 }
884
885 graph_error_t
886 hwgraph_vertex_unref(vertex_hdl_t vhdl)
887 {
888         return(GRAPH_ILLEGAL_REQUEST);
889 }
890
891 void
892 hwgraph_debug(char *file, char * function, int line, vertex_hdl_t vhdl1, vertex_hdl_t vhdl2, char *format, ...)
893 {
894
895         int pos;
896         char *hwpath;
897         va_list ap;
898
899         if ( !hwgraph_debug_mask )
900                 return;
901
902         hwpath = kmalloc(MAXDEVNAME, GFP_KERNEL);
903         if (!hwpath)
904                 BUG();
905
906         printk("HWGRAPH_DEBUG %s %s %d : ", file, function, line);
907
908         if (vhdl1){
909                 memset(hwpath, 0, MAXDEVNAME);
910                 pos = hwgfs_generate_path(vhdl1, hwpath, MAXDEVNAME);
911                 printk("vhdl1 = %s : ", &hwpath[pos]);
912         }
913
914         if (vhdl2){
915                 memset(hwpath, 0, MAXDEVNAME);
916                 pos = hwgfs_generate_path(vhdl2, hwpath, MAXDEVNAME);
917                 printk("vhdl2 = %s :", &hwpath[pos]);
918         }
919
920         memset(hwpath, 0, MAXDEVNAME);
921         va_start(ap, format);
922         vsnprintf(hwpath, 500, format, ap);
923         va_end(ap);
924         hwpath[MAXDEVNAME -1] = (char)0; /* Just in case. */
925         printk(" %s", hwpath);
926         kfree(hwpath);
927 }
928
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);