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  */
hcl_open(struct inode * inode,struct file * filp)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 
hcl_close(struct inode * inode,struct file * filp)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 
hcl_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)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  */
init_hcl(void)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  */
hcl_setup(char * str)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
hwgraph_generate_path(vertex_hdl_t de,char * path,int buflen)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
hwgraph_fastinfo_set(vertex_hdl_t de,arbitrary_info_t fastinfo)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
hwgraph_fastinfo_get(vertex_hdl_t de)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
hwgraph_connectpt_set(vertex_hdl_t de,vertex_hdl_t connect_de)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
hwgraph_connectpt_get(vertex_hdl_t de)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
hwgraph_mk_dir(vertex_hdl_t de,const char * name,unsigned int namelen,void * info)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
hwgraph_path_add(vertex_hdl_t fromv,char * path,vertex_hdl_t * new_de)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
hwgraph_register(vertex_hdl_t de,const char * name,unsigned int namelen,unsigned int flags,unsigned int major,unsigned int minor,umode_t mode,uid_t uid,gid_t gid,struct file_operations * fops,void * info)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
hwgraph_mk_symlink(vertex_hdl_t de,const char * name,unsigned int namelen,unsigned int flags,const char * link,unsigned int linklen,vertex_hdl_t * handle,void * info)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
hwgraph_vertex_destroy(vertex_hdl_t de)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
hwgraph_edge_add(vertex_hdl_t from,vertex_hdl_t to,char * name)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
hwgraph_edge_get(vertex_hdl_t from,char * name,vertex_hdl_t * toptr)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
hwgraph_info_add_LBL(vertex_hdl_t de,char * name,arbitrary_info_t info)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
hwgraph_info_remove_LBL(vertex_hdl_t de,char * name,arbitrary_info_t * old_info)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
hwgraph_info_replace_LBL(vertex_hdl_t de,char * name,arbitrary_info_t info,arbitrary_info_t * old_info)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
hwgraph_info_get_LBL(vertex_hdl_t de,char * name,arbitrary_info_t * infop)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
hwgraph_info_get_exported_LBL(vertex_hdl_t de,char * name,int * export_info,arbitrary_info_t * infop)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
hwgraph_info_get_next_LBL(vertex_hdl_t de,char * buf,arbitrary_info_t * infop,labelcl_info_place_t * place)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
hwgraph_info_export_LBL(vertex_hdl_t de,char * name,int nbytes)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
hwgraph_info_unexport_LBL(vertex_hdl_t de,char * name)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
hwgraph_path_lookup(vertex_hdl_t start_vertex_handle,char * lookup_path,vertex_hdl_t * vertex_handle_ptr,char ** remainder)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
hwgraph_traverse(vertex_hdl_t de,char * path,vertex_hdl_t * found)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
hwgraph_path_to_vertex(char * path)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
hwgraph_inventory_remove(vertex_hdl_t de,int class,int type,major_t controller,minor_t unit,int state)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
hwgraph_vertex_name_get(vertex_hdl_t vhdl,char * buf,uint buflen)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 *
vertex_to_name(vertex_hdl_t vhdl,char * buf,uint buflen)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
hwgraph_edge_remove(vertex_hdl_t from,char * name,vertex_hdl_t * toptr)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
hwgraph_vertex_unref(vertex_hdl_t vhdl)886 hwgraph_vertex_unref(vertex_hdl_t vhdl)
887 {
888 	return(GRAPH_ILLEGAL_REQUEST);
889 }
890 
891 void
hwgraph_debug(char * file,char * function,int line,vertex_hdl_t vhdl1,vertex_hdl_t vhdl2,char * format,...)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);
948