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/hcl.h>
27 #include <asm/sn/labelcl.h>
28 #include <asm/sn/simulator.h>
30 #define vertex_hdl_t hwgfs_handle_t
32 vertex_hdl_t hwgraph_root;
33 vertex_hdl_t linux_busnum;
34 extern int pci_bus_cvlink_init(void);
35 unsigned long hwgraph_debug_mask;
38 * init_hcl() - Boot time initialization.
41 int __init init_hcl(void)
43 extern void string_table_init(struct string_table *);
44 extern struct string_table label_string_table;
45 extern int init_ioconfig_bus(void);
46 extern int init_hwgfs_fs(void);
52 * Create the hwgraph_root.
54 rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root);
56 printk("init_hcl: Failed to create hwgraph_root.\n");
61 * Initialize the HCL string table.
64 string_table_init(&label_string_table);
67 * Create the directory that links Linux bus numbers to our Xwidget.
69 rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum);
70 if (linux_busnum == NULL) {
71 printk("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS);
75 if (pci_bus_cvlink_init() < 0 ) {
76 printk("init_hcl: Failed to create pcibus cvlink.\n");
89 * Get device specific "fast information".
93 hwgraph_fastinfo_get(vertex_hdl_t de)
95 arbitrary_info_t fastinfo;
99 printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n");
104 rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo);
113 * hwgraph_connectpt_get: Returns the entry's connect point.
117 hwgraph_connectpt_get(vertex_hdl_t de)
120 arbitrary_info_t info;
121 vertex_hdl_t connect;
123 rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
128 connect = (vertex_hdl_t)info;
135 * hwgraph_mk_dir - Creates a directory entry.
138 hwgraph_mk_dir(vertex_hdl_t de, const char *name,
139 unsigned int namelen, void *info)
143 labelcl_info_t *labelcl_info = NULL;
144 vertex_hdl_t new_handle = NULL;
145 vertex_hdl_t parent = NULL;
148 * Create the device info structure for hwgraph compatiblity support.
150 labelcl_info = labelcl_info_create();
157 new_handle = hwgfs_mk_dir(de, name, (void *)labelcl_info);
159 labelcl_info_destroy(labelcl_info);
164 * Get the parent handle.
166 parent = hwgfs_get_parent (new_handle);
169 * To provide the same semantics as the hwgraph, set the connect point.
171 rv = hwgraph_connectpt_set(new_handle, parent);
174 * We need to clean up!
179 * If the caller provides a private data pointer, save it in the
180 * labelcl info structure(fastinfo). This can be retrieved via
181 * hwgraph_fastinfo_get()
184 hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info);
191 * hwgraph_path_add - Create a directory node with the given path starting
192 * from the given fromv.
195 hwgraph_path_add(vertex_hdl_t fromv,
197 vertex_hdl_t *new_de)
200 unsigned int namelen = strlen(path);
204 * We need to handle the case when fromv is NULL ..
205 * in this case we need to create the path from the
209 fromv = hwgraph_root;
212 * check the entry doesn't already exist, if it does
213 * then we simply want new_de to point to it (otherwise
214 * we'll overwrite the existing labelcl_info struct)
216 rv = hwgraph_edge_get(fromv, path, new_de);
217 if (rv) { /* couldn't find entry so we create it */
218 *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL);
230 * hwgraph_register - Creates a special device file.
234 hwgraph_register(vertex_hdl_t de, const char *name,
235 unsigned int namelen, unsigned int flags,
236 unsigned int major, unsigned int minor,
237 umode_t mode, uid_t uid, gid_t gid,
238 struct file_operations *fops,
242 vertex_hdl_t new_handle = NULL;
247 new_handle = hwgfs_register(de, name, flags, major,
248 minor, mode, fops, info);
256 * hwgraph_mk_symlink - Create a symbolic link.
259 hwgraph_mk_symlink(vertex_hdl_t de, const char *name, unsigned int namelen,
260 unsigned int flags, const char *link, unsigned int linklen,
261 vertex_hdl_t *handle, void *info)
264 void *labelcl_info = NULL;
266 vertex_hdl_t new_handle = NULL;
269 * Create the labelcl info structure for hwgraph compatiblity support.
271 labelcl_info = labelcl_info_create();
276 * Create a symbolic link.
278 status = hwgfs_mk_symlink(de, name, flags, link,
279 &new_handle, labelcl_info);
280 if ( (!new_handle) || (!status) ){
281 labelcl_info_destroy((labelcl_info_t *)labelcl_info);
286 * If the caller provides a private data pointer, save it in the
287 * labelcl info structure(fastinfo). This can be retrieved via
288 * hwgraph_fastinfo_get()
291 hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info);
293 *handle = new_handle;
299 * hwgraph_vertex_destroy - Destroy the entry
302 hwgraph_vertex_destroy(vertex_hdl_t de)
305 void *labelcl_info = NULL;
307 labelcl_info = hwgfs_get_info(de);
308 hwgfs_unregister(de);
311 labelcl_info_destroy((labelcl_info_t *)labelcl_info);
317 hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name)
323 vertex_hdl_t handle = NULL;
327 path = kmalloc(1024, GFP_KERNEL);
330 memset((char *)path, 0x0, 1024);
331 link = kmalloc(1024, GFP_KERNEL);
336 memset((char *)link, 0x0, 1024);
338 i = hwgfs_generate_path (from, path, 1024);
342 index = strstr (s1, "/");
352 for (i = 0; i < count; i++) {
353 strcat((char *)link,"../");
356 memset(path, 0x0, 1024);
357 i = hwgfs_generate_path (to, path, 1024);
358 strcat((char *)link, (char *)path);
361 * Otherwise, just create a symlink to the vertex.
362 * In this case the vertex was previous created with a REAL pathname.
364 rv = hwgfs_mk_symlink (from, (const char *)name,
377 hwgraph_edge_get(vertex_hdl_t from, char *name, vertex_hdl_t *toptr)
380 vertex_hdl_t target_handle = NULL;
389 * If the name is "." just return the current entry handle.
391 if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) {
395 } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) {
397 * Hmmm .. should we return the connect point or parent ..
398 * see in hwgraph, the concept of parent is the connectpt!
400 * Maybe we should see whether the connectpt is set .. if
401 * not just return the parent!
403 target_handle = hwgraph_connectpt_get(from);
406 * Just return the connect point.
408 *toptr = target_handle;
411 target_handle = hwgfs_get_parent(from);
412 *toptr = target_handle;
415 target_handle = hwgfs_find_handle (from, name, 0, 0,
416 0, 1); /* Yes traverse symbolic links */
419 if (target_handle == NULL)
422 *toptr = target_handle;
428 * hwgraph_info_add_LBL - Adds a new label for the device. Mark the info_desc
429 * of the label as INFO_DESC_PRIVATE and store the info in the label.
433 hwgraph_info_add_LBL( vertex_hdl_t de,
435 arbitrary_info_t info)
437 return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info));
441 * hwgraph_info_remove_LBL - Remove the label entry for the device.
445 hwgraph_info_remove_LBL( vertex_hdl_t de,
447 arbitrary_info_t *old_info)
449 return(labelcl_info_remove_LBL(de, name, NULL, old_info));
453 * hwgraph_info_replace_LBL - replaces an existing label with
454 * a new label info value.
458 hwgraph_info_replace_LBL( vertex_hdl_t de,
460 arbitrary_info_t info,
461 arbitrary_info_t *old_info)
463 return(labelcl_info_replace_LBL(de, name,
464 INFO_DESC_PRIVATE, info,
468 * hwgraph_info_get_LBL - Get and return the info value in the label of the
473 hwgraph_info_get_LBL(vertex_hdl_t de,
475 arbitrary_info_t *infop)
477 return(labelcl_info_get_LBL(de, name, NULL, infop));
481 * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer
482 * of the given label for the device. The weird thing is that the label
483 * that matches the name is return irrespective of the info_desc value!
484 * Do not understand why the word "exported" is used!
488 hwgraph_info_get_exported_LBL(vertex_hdl_t de,
491 arbitrary_info_t *infop)
494 arb_info_desc_t info_desc;
496 rc = labelcl_info_get_LBL(de, name, &info_desc, infop);
498 *export_info = (int)info_desc;
504 * hwgraph_info_get_next_LBL - Returns the next label info given the
505 * current label entry in place.
507 * Once again this has no locking or reference count for protection.
512 hwgraph_info_get_next_LBL(vertex_hdl_t de,
514 arbitrary_info_t *infop,
515 labelcl_info_place_t *place)
517 return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place));
521 * hwgraph_info_export_LBL - Retrieve the specified label entry and modify
522 * the info_desc field with the given value in nbytes.
526 hwgraph_info_export_LBL(vertex_hdl_t de, char *name, int nbytes)
528 arbitrary_info_t info;
532 nbytes = INFO_DESC_EXPORT;
537 rc = labelcl_info_get_LBL(de, name, NULL, &info);
541 rc = labelcl_info_replace_LBL(de, name,
542 nbytes, info, NULL, NULL);
548 * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the
549 * label info_descr filed to INFO_DESC_PRIVATE.
553 hwgraph_info_unexport_LBL(vertex_hdl_t de, char *name)
555 arbitrary_info_t info;
558 rc = labelcl_info_get_LBL(de, name, NULL, &info);
562 rc = labelcl_info_replace_LBL(de, name,
563 INFO_DESC_PRIVATE, info, NULL, NULL);
569 * hwgraph_traverse - Find and return the handle starting from de.
573 hwgraph_traverse(vertex_hdl_t de, char *path, vertex_hdl_t *found)
576 * get the directory entry (path should end in a directory)
579 *found = hwgfs_find_handle(de, /* start dir */
583 0, /* char | block */
584 1); /* traverse symlinks */
586 return(GRAPH_NOT_FOUND);
588 return(GRAPH_SUCCESS);
592 * Find the canonical name for a given vertex by walking back through
593 * connectpt's until we hit the hwgraph root vertex (or until we run
594 * out of buffer space or until something goes wrong).
596 * COMPATIBILITY FUNCTIONALITY
597 * Walks back through 'parents', not necessarily the same as connectpts.
599 * Need to resolve the fact that does not return the path from
600 * "/" but rather it just stops right before /dev ..
603 hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, unsigned int buflen)
609 return(-1); /* XXX should be GRAPH_BAD_PARAM ? */
611 locbuf = kmalloc(buflen, GFP_KERNEL);
613 pos = hwgfs_generate_path(vhdl, locbuf, buflen);
619 strcpy(buf, &locbuf[pos]);
625 ** vertex_to_name converts a vertex into a canonical name by walking
626 ** back through connect points until we hit the hwgraph root (or until
627 ** we run out of buffer space).
629 ** Usually returns a pointer to the original buffer, filled in as
630 ** appropriate. If the buffer is too small to hold the entire name,
631 ** or if anything goes wrong while determining the name, vertex_to_name
632 ** returns "UnknownDevice".
635 #define DEVNAME_UNKNOWN "UnknownDevice"
638 vertex_to_name(vertex_hdl_t vhdl, char *buf, unsigned int buflen)
640 if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS)
643 return(DEVNAME_UNKNOWN);
648 hwgraph_debug(char *file, const char * function, int line, vertex_hdl_t vhdl1, vertex_hdl_t vhdl2, char *format, ...)
655 if ( !hwgraph_debug_mask )
658 hwpath = kmalloc(MAXDEVNAME, GFP_KERNEL);
660 printk("HWGRAPH_DEBUG kmalloc fails at %d ", __LINE__);
664 printk("HWGRAPH_DEBUG %s %s %d : ", file, function, line);
667 memset(hwpath, 0, MAXDEVNAME);
668 pos = hwgfs_generate_path(vhdl1, hwpath, MAXDEVNAME);
669 printk("vhdl1 = %s : ", &hwpath[pos]);
673 memset(hwpath, 0, MAXDEVNAME);
674 pos = hwgfs_generate_path(vhdl2, hwpath, MAXDEVNAME);
675 printk("vhdl2 = %s :", &hwpath[pos]);
678 memset(hwpath, 0, MAXDEVNAME);
679 va_start(ap, format);
680 vsnprintf(hwpath, 500, format, ap);
682 hwpath[MAXDEVNAME -1] = (char)0; /* Just in case. */
683 printk(" %s", hwpath);
687 EXPORT_SYMBOL(hwgraph_mk_dir);
688 EXPORT_SYMBOL(hwgraph_path_add);
689 EXPORT_SYMBOL(hwgraph_register);
690 EXPORT_SYMBOL(hwgraph_vertex_destroy);
691 EXPORT_SYMBOL(hwgraph_fastinfo_get);
692 EXPORT_SYMBOL(hwgraph_connectpt_get);
693 EXPORT_SYMBOL(hwgraph_info_add_LBL);
694 EXPORT_SYMBOL(hwgraph_info_remove_LBL);
695 EXPORT_SYMBOL(hwgraph_info_replace_LBL);
696 EXPORT_SYMBOL(hwgraph_info_get_LBL);
697 EXPORT_SYMBOL(hwgraph_info_get_exported_LBL);
698 EXPORT_SYMBOL(hwgraph_info_get_next_LBL);
699 EXPORT_SYMBOL(hwgraph_info_export_LBL);
700 EXPORT_SYMBOL(hwgraph_info_unexport_LBL);
701 EXPORT_SYMBOL(hwgraph_traverse);
702 EXPORT_SYMBOL(hwgraph_vertex_name_get);