hcl.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:36k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id$
  2.  *
  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.
  6.  *
  7.  *  hcl - SGI's Hardware Graph compatibility layer.
  8.  *
  9.  * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
  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 <asm/sn/sgi.h>
  18. #include <linux/devfs_fs.h>
  19. #include <linux/devfs_fs_kernel.h>
  20. #include <asm/io.h>
  21. #include <asm/sn/iograph.h>
  22. #include <asm/sn/invent.h>
  23. #include <asm/sn/hcl.h>
  24. #include <asm/sn/labelcl.h>
  25. #define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER"
  26. #define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE"
  27. #define HCL_TEMP_NAME_LEN 44 
  28. #define HCL_VERSION "1.0"
  29. devfs_handle_t hwgraph_root = NULL;
  30. devfs_handle_t linux_busnum = NULL;
  31. /*
  32.  * Debug flag definition.
  33.  */
  34. #define OPTION_NONE             0x00
  35. #define HCL_DEBUG_NONE 0x00000
  36. #define HCL_DEBUG_ALL  0x0ffff
  37. #if defined(CONFIG_HCL_DEBUG)
  38. static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE;
  39. #endif
  40. static unsigned int hcl_debug = HCL_DEBUG_NONE;
  41. #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
  42. static unsigned int boot_options = OPTION_NONE;
  43. #endif
  44. /*
  45.  * Some Global definitions.
  46.  */
  47. devfs_handle_t hcl_handle = NULL;
  48. invplace_t invplace_none = {
  49. GRAPH_VERTEX_NONE,
  50. GRAPH_VERTEX_PLACE_NONE,
  51. NULL
  52. };
  53. /*
  54.  * HCL device driver.
  55.  * The purpose of this device driver is to provide a facility 
  56.  * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path 
  57.  * to manipulate label entries without having to implement
  58.  * system call interfaces.  This methodology will enable us to 
  59.  * make this feature module loadable.
  60.  */
  61. static int hcl_open(struct inode * inode, struct file * filp)
  62. {
  63. if (hcl_debug) {
  64.          printk("HCL: hcl_open called.n");
  65. }
  66.         return(0);
  67. }
  68. static int hcl_close(struct inode * inode, struct file * filp)
  69. {
  70. if (hcl_debug) {
  71.          printk("HCL: hcl_close called.n");
  72. }
  73.         return(0);
  74. }
  75. static int hcl_ioctl(struct inode * inode, struct file * file,
  76.         unsigned int cmd, unsigned long arg)
  77. {
  78. if (hcl_debug) {
  79. printk("HCL: hcl_ioctl called.n");
  80. }
  81. switch (cmd) {
  82. default:
  83. if (hcl_debug) {
  84. printk("HCL: hcl_ioctl cmd = 0x%xn", cmd);
  85. }
  86. }
  87. return(0);
  88. }
  89. struct file_operations hcl_fops = {
  90. (struct module *)0,
  91. NULL, /* lseek - default */
  92. NULL, /* read - general block-dev read */
  93. NULL, /* write - general block-dev write */
  94. NULL, /* readdir - bad */
  95. NULL, /* poll */
  96. hcl_ioctl,      /* ioctl */
  97. NULL, /* mmap */
  98. hcl_open, /* open */
  99. NULL, /* flush */
  100. hcl_close, /* release */
  101. NULL, /* fsync */
  102. NULL, /* fasync */
  103. NULL, /* lock */
  104. NULL, /* readv */
  105. NULL, /* writev */
  106. };
  107. /*
  108.  * init_hcl() - Boot time initialization.  Ensure that it is called 
  109.  * after devfs has been initialized.
  110.  *
  111.  * For now this routine is being called out of devfs/base.c.  Actually 
  112.  * Not a bad place to be ..
  113.  *
  114.  */
  115. #ifdef MODULE
  116. int init_module (void)
  117. #else
  118. int __init init_hcl(void)
  119. #endif
  120. {
  121. extern void string_table_init(struct string_table *);
  122. extern struct string_table label_string_table;
  123. extern int init_ifconfig_net(void);
  124. int rv = 0;
  125. #if defined(CONFIG_HCL_DEBUG) && !defined(MODULE)
  126. printk ("n%s: v%s Colin Ngam (cngam@sgi.com)n",
  127. HCL_NAME, HCL_VERSION);
  128. hcl_debug = hcl_debug_init;
  129. printk ("%s: hcl_debug: 0x%0xn", HCL_NAME, hcl_debug);
  130. printk ("n%s: boot_options: 0x%0xn", HCL_NAME, boot_options);
  131. #endif
  132. /*
  133.  * Create the hwgraph_root on devfs.
  134.  */
  135. rv = hwgraph_path_add(NULL, "hw", &hwgraph_root);
  136. if (rv)
  137. printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.n", rv);
  138. /*
  139.  * Create the hcl driver to support inventory entry manipulations.
  140.  * By default, it is expected that devfs is mounted on /dev.
  141.  *
  142.  */
  143. hcl_handle = hwgraph_register(hwgraph_root, ".hcl",
  144. 0, DEVFS_FL_AUTO_DEVNUM,
  145. 0, 0,
  146. S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
  147. &hcl_fops, NULL);
  148. if (hcl_handle == NULL) {
  149. panic("HCL: Unable to create HCL Driver in init_hcl().n");
  150. return(0);
  151. }
  152. /*
  153.  * Initialize the HCL string table.
  154.  */
  155. string_table_init(&label_string_table);
  156. /*
  157.  * Create the directory that links Linux bus numbers to our Xwidget.
  158.  */
  159. rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum);
  160. if (linux_busnum == NULL) {
  161. panic("HCL: Unable to create hw/linux/busnumn");
  162. return(0);
  163. }
  164. /*
  165.  * Initialize the ifconfgi_net driver that does network devices 
  166.  * Persistent Naming.
  167.  */
  168. init_ifconfig_net();
  169. return(0);
  170. }
  171. /*
  172.  * hcl_setup() - Process boot time parameters if given.
  173.  * "hcl="
  174.  * This routine gets called only if "hcl=" is given in the 
  175.  * boot line and before init_hcl().
  176.  *
  177.  * We currently do not have any boot options .. when we do, 
  178.  * functionalities can be added here.
  179.  *
  180.  */
  181. static int __init hcl_setup(char *str)
  182. {
  183.     while ( (*str != '') && !isspace (*str) )
  184.     {
  185. #ifdef CONFIG_HCL_DEBUG
  186.         if (strncmp (str, "all", 3) == 0) {
  187.             hcl_debug_init |= HCL_DEBUG_ALL;
  188.             str += 3;
  189.         } else 
  190.          return 0;
  191. #endif
  192.         if (*str != ',') return 0;
  193.         ++str;
  194.     }
  195.     return 1;
  196. }
  197. __setup("hcl=", hcl_setup);
  198. /*
  199.  * Set device specific "fast information".
  200.  *
  201.  */
  202. void
  203. hwgraph_fastinfo_set(devfs_handle_t de, arbitrary_info_t fastinfo)
  204. {
  205. if (hcl_debug) {
  206. printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ldn", (void *)de, fastinfo);
  207. }
  208. labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL);
  209. }
  210. /*
  211.  * Get device specific "fast information".
  212.  *
  213.  */
  214. arbitrary_info_t
  215. hwgraph_fastinfo_get(devfs_handle_t de)
  216. {
  217. arbitrary_info_t fastinfo;
  218. int rv;
  219. if (!de) {
  220. printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.n");
  221. return(-1);
  222. }
  223. rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo);
  224. if (rv == 0)
  225. return(fastinfo);
  226. return(0);
  227. }
  228. /*
  229.  * hwgraph_connectpt_set - Sets the connect point handle in de to the 
  230.  * given connect_de handle.  By default, the connect point of the 
  231.  * devfs node is the parent.  This effectively changes this assumption.
  232.  */
  233. int
  234. hwgraph_connectpt_set(devfs_handle_t de, devfs_handle_t connect_de)
  235. {
  236. int rv;
  237. if (!de)
  238. return(-1);
  239. rv = labelcl_info_connectpt_set(de, connect_de);
  240. return(rv);
  241. }
  242. /*
  243.  * hwgraph_connectpt_get: Returns the entry's connect point  in the devfs 
  244.  * tree.
  245.  */
  246. devfs_handle_t
  247. hwgraph_connectpt_get(devfs_handle_t de)
  248. {
  249. int rv;
  250. arbitrary_info_t info;
  251. devfs_handle_t connect;
  252. rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
  253. if (rv != 0) {
  254. return(NULL);
  255. }
  256. connect = (devfs_handle_t)info;
  257. return(connect);
  258. }
  259. /*
  260.  * hwgraph_mk_dir - Creates a directory entry with devfs.
  261.  * Note that a directory entry in devfs can have children 
  262.  * but it cannot be a char|block special file.
  263.  */
  264. devfs_handle_t
  265. hwgraph_mk_dir(devfs_handle_t de, const char *name,
  266.                 unsigned int namelen, void *info)
  267. {
  268. int rv;
  269. labelcl_info_t *labelcl_info = NULL;
  270. devfs_handle_t new_devfs_handle = NULL;
  271. devfs_handle_t parent = NULL;
  272. /*
  273.  * Create the device info structure for hwgraph compatiblity support.
  274.  */
  275. labelcl_info = labelcl_info_create();
  276. if (!labelcl_info)
  277. return(NULL);
  278. /*
  279.  * Create a devfs entry.
  280.  */
  281. new_devfs_handle = devfs_mk_dir(de, name, (void *)labelcl_info);
  282. if (!new_devfs_handle) {
  283. labelcl_info_destroy(labelcl_info);
  284. return(NULL);
  285. }
  286. /*
  287.  * Get the parent handle.
  288.  */
  289. parent = devfs_get_parent (new_devfs_handle);
  290. /*
  291.  * To provide the same semantics as the hwgraph, set the connect point.
  292.  */
  293. rv = hwgraph_connectpt_set(new_devfs_handle, parent);
  294. if (!rv) {
  295. /*
  296.  * We need to clean up!
  297.  */
  298. }
  299. /*
  300.  * If the caller provides a private data pointer, save it in the 
  301.  * labelcl info structure(fastinfo).  This can be retrieved via
  302.  * hwgraph_fastinfo_get()
  303.  */
  304. if (info)
  305. hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info);
  306. return(new_devfs_handle);
  307. }
  308. /*
  309.  * hwgraph_vertex_create - Create a vertex by giving it a temp name.
  310.  */
  311. /*
  312.  * hwgraph_path_add - Create a directory node with the given path starting 
  313.  * from the given devfs_handle_t.
  314.  */
  315. extern char * dev_to_name(devfs_handle_t, char *, uint);
  316. int
  317. hwgraph_path_add(devfs_handle_t  fromv,
  318.  char *path,
  319.  devfs_handle_t *new_de)
  320. {
  321. unsigned int namelen = strlen(path);
  322. int rv;
  323. /*
  324.  * We need to handle the case when fromv is NULL ..
  325.  * in this case we need to create the path from the 
  326.  * hwgraph root!
  327.  */
  328. if (fromv == NULL)
  329. fromv = hwgraph_root;
  330. /*
  331.  * check the entry doesn't already exist, if it does
  332.  * then we simply want new_de to point to it (otherwise
  333.  * we'll overwrite the existing labelcl_info struct)
  334.  */
  335. rv = hwgraph_edge_get(fromv, path, new_de);
  336. if (rv) { /* couldn't find entry so we create it */
  337. *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL);
  338. if (new_de == NULL)
  339. return(-1);
  340. else
  341. return(0);
  342. }
  343. else 
  344.   return(0);
  345. }
  346. /*
  347.  * hwgraph_register  - Creates a file entry with devfs.
  348.  * Note that a file entry cannot have children .. it is like a 
  349.  * char|block special vertex in hwgraph.
  350.  */
  351. devfs_handle_t
  352. hwgraph_register(devfs_handle_t de, const char *name,
  353.                 unsigned int namelen, unsigned int flags, 
  354. unsigned int major, unsigned int minor,
  355.                 umode_t mode, uid_t uid, gid_t gid, 
  356. struct file_operations *fops,
  357.                 void *info)
  358. {
  359. int rv;
  360.         void *labelcl_info = NULL;
  361.         devfs_handle_t new_devfs_handle = NULL;
  362. devfs_handle_t parent = NULL;
  363.         /*
  364.          * Create the labelcl info structure for hwgraph compatiblity support.
  365.          */
  366.         labelcl_info = labelcl_info_create();
  367.         if (!labelcl_info)
  368.                 return(NULL);
  369.         /*
  370.          * Create a devfs entry.
  371.          */
  372.         new_devfs_handle = devfs_register(de, name, flags, major,
  373. minor, mode, fops, labelcl_info);
  374.         if (!new_devfs_handle) {
  375.                 labelcl_info_destroy((labelcl_info_t *)labelcl_info);
  376.                 return(NULL);
  377.         }
  378. /*
  379.  * Get the parent handle.
  380.  */
  381. if (de == NULL)
  382. parent = devfs_get_parent (new_devfs_handle);
  383. else
  384. parent = de;
  385. /*
  386.  * To provide the same semantics as the hwgraph, set the connect point.
  387.  */
  388. rv = hwgraph_connectpt_set(new_devfs_handle, parent);
  389. if (rv) {
  390. /*
  391.  * We need to clean up!
  392.  */
  393. printk(KERN_WARNING "HCL: Unable to set the connect point to it's parent 0x%pn",
  394. (void *)new_devfs_handle);
  395. }
  396.         /*
  397.          * If the caller provides a private data pointer, save it in the 
  398.          * labelcl info structure(fastinfo).  This can be retrieved via
  399.          * hwgraph_fastinfo_get()
  400.          */
  401.         if (info)
  402.                 hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info);
  403.         return(new_devfs_handle);
  404. }
  405. /*
  406.  * hwgraph_mk_symlink - Create a symbolic link.
  407.  */
  408. int
  409. hwgraph_mk_symlink(devfs_handle_t de, const char *name, unsigned int namelen,
  410.                 unsigned int flags, const char *link, unsigned int linklen, 
  411. devfs_handle_t *handle, void *info)
  412. {
  413. void *labelcl_info = NULL;
  414. int status = 0;
  415. devfs_handle_t new_devfs_handle = NULL;
  416. /*
  417.  * Create the labelcl info structure for hwgraph compatiblity support.
  418.  */
  419. labelcl_info = labelcl_info_create();
  420. if (!labelcl_info)
  421. return(-1);
  422. /*
  423.  * Create a symbolic link devfs entry.
  424.  */
  425. status = devfs_mk_symlink(de, name, flags, link,
  426. &new_devfs_handle, labelcl_info);
  427. if ( (!new_devfs_handle) || (!status) ){
  428. labelcl_info_destroy((labelcl_info_t *)labelcl_info);
  429. return(-1);
  430. }
  431. /*
  432.  * If the caller provides a private data pointer, save it in the 
  433.  * labelcl info structure(fastinfo).  This can be retrieved via
  434.  * hwgraph_fastinfo_get()
  435.  */
  436. if (info)
  437. hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info);
  438. *handle = new_devfs_handle;
  439. return(0);
  440. }
  441. /*
  442.  * hwgraph_vertex_get_next - this routine returns the next sibbling for the 
  443.  * device entry given in de.  If there are no more sibbling, NULL 
  444.  *  is returned in next_sibbling.
  445.  *
  446.  * Currently we do not have any protection against de being deleted 
  447.  * while it's handle is being held.
  448.  */
  449. int
  450. hwgraph_vertex_get_next(devfs_handle_t *next_sibbling, devfs_handle_t *de)
  451. {
  452. *next_sibbling = devfs_get_next_sibling (*de);
  453. if (*next_sibbling != NULL)
  454. *de = *next_sibbling;
  455. return (0);
  456. }
  457. /*
  458.  * hwgraph_vertex_destroy - Destroy the devfs entry
  459.  */
  460. int
  461. hwgraph_vertex_destroy(devfs_handle_t de)
  462. {
  463. void *labelcl_info = NULL;
  464. labelcl_info = devfs_get_info(de);
  465. devfs_unregister(de);
  466. if (labelcl_info)
  467. labelcl_info_destroy((labelcl_info_t *)labelcl_info);
  468. return(0);
  469. }
  470. /*
  471. ** See if a vertex has an outgoing edge with a specified name.
  472. ** Vertices in the hwgraph *implicitly* contain these edges:
  473. ** "."  refers to "current vertex"
  474. ** ".."  refers to "connect point vertex"
  475. ** "char" refers to current vertex (character device access)
  476. ** "block" refers to current vertex (block device access)
  477. */
  478. /*
  479.  * hwgraph_edge_add - This routines has changed from the original conext.
  480.  * All it does now is to create a symbolic link from "from" to "to".
  481.  */
  482. /* ARGSUSED */
  483. int
  484. hwgraph_edge_add(devfs_handle_t from, devfs_handle_t to, char *name)
  485. {
  486. char *path;
  487. char *s1;
  488. char *index;
  489. int name_start;
  490. devfs_handle_t handle = NULL;
  491. int rv;
  492. int i, count;
  493. path = kmalloc(1024, GFP_KERNEL);
  494. memset(path, 0x0, 1024);
  495. name_start = devfs_generate_path (from, path, 1024);
  496. s1 = &path[name_start];
  497. count = 0;
  498. while (1) {
  499. index = strstr (s1, "/");
  500. if (index) {
  501. count++;
  502. s1 = ++index;
  503. } else {
  504. count++;
  505. break;
  506. }
  507. }
  508. memset(path, 0x0, 1024);
  509. name_start = devfs_generate_path (to, path, 1024);
  510. for (i = 0; i < count; i++) {
  511. strcat(path,"../");
  512. }
  513. strcat(path, &path[name_start]);
  514. /*
  515.  * Otherwise, just create a symlink to the vertex.
  516.  * In this case the vertex was previous created with a REAL pathname.
  517.  */
  518. rv = devfs_mk_symlink (from, (const char *)name, 
  519.        DEVFS_FL_DEFAULT, path,
  520.        &handle, NULL);
  521. name_start = devfs_generate_path (handle, path, 1024);
  522. return(rv);
  523. }
  524. /* ARGSUSED */
  525. int
  526. hwgraph_edge_get(devfs_handle_t from, char *name, devfs_handle_t *toptr)
  527. {
  528. int namelen = 0;
  529. devfs_handle_t target_handle = NULL;
  530. if (name == NULL)
  531. return(-1);
  532. if (toptr == NULL)
  533. return(-1);
  534. /*
  535.  * If the name is "." just return the current devfs entry handle.
  536.  */
  537. if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) {
  538. if (toptr) {
  539. *toptr = from;
  540. }
  541. } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) {
  542. /*
  543.  * Hmmm .. should we return the connect point or parent ..
  544.  * see in hwgraph, the concept of parent is the connectpt!
  545.  *
  546.  * Maybe we should see whether the connectpt is set .. if 
  547.  * not just return the parent!
  548.  */
  549. target_handle = hwgraph_connectpt_get(from);
  550. if (target_handle) {
  551. /*
  552.  * Just return the connect point.
  553.  */
  554. *toptr = target_handle;
  555. return(0);
  556. }
  557. target_handle = devfs_get_parent(from);
  558. *toptr = target_handle;
  559. } else {
  560. /*
  561.  * Call devfs to get the devfs entry.
  562.  */
  563. namelen = (int) strlen(name);
  564. target_handle = devfs_find_handle (from, name, 0, 0,
  565. 0, 1); /* Yes traverse symbolic links */
  566. if (target_handle == NULL)
  567. return(-1);
  568. else
  569. *toptr = target_handle;
  570. }
  571. return(0);
  572. }
  573. /*
  574.  * hwgraph_edge_get_next - Retrieves the next sibbling given the current
  575.  * entry number "placeptr".
  576.  *
  577.  *  Allow the caller to retrieve walk through the sibblings of "source" 
  578.  *  devfs_handle_t.  The implicit edges "." and ".." is returned first 
  579.  *  followed by each of the real children.
  580.  *
  581.  * We may end up returning garbage if another thread perform any deletion 
  582.  * in this directory before "placeptr".
  583.  *
  584.  */
  585. /* ARGSUSED */
  586. int
  587. hwgraph_edge_get_next(devfs_handle_t source, char *name, devfs_handle_t *target,
  588.                               uint *placeptr)
  589. {
  590.         uint which_place;
  591. unsigned int namelen = 0;
  592. const char *tempname = NULL;
  593.         if (placeptr == NULL)
  594.                 return(-1);
  595.         which_place = *placeptr;
  596. again:
  597.         if (which_place <= HWGRAPH_RESERVED_PLACES) {
  598.                 if (which_place == EDGE_PLACE_WANT_CURRENT) {
  599. /*
  600.  * Looking for "."
  601.  * Return the current devfs handle.
  602.  */
  603.                         if (name != NULL)
  604.                                 strcpy(name, HWGRAPH_EDGELBL_DOT);
  605.                         if (target != NULL) {
  606.                                 *target = source; 
  607. /* XXX should incr "source" ref count here if we
  608.  * ever implement ref counts */
  609.                         }
  610.                 } else if (which_place == EDGE_PLACE_WANT_CONNECTPT) {
  611. /*
  612.  * Looking for the connect point or parent.
  613.  * If the connect point is set .. it returns the connect point.
  614.  * Otherwise, it returns the parent .. will we support 
  615.  * connect point?
  616.  */
  617.                         devfs_handle_t connect_point = hwgraph_connectpt_get(source);
  618.                         if (connect_point == NULL) {
  619. /*
  620.  * No connectpoint set .. either the User
  621.  * explicitly NULL it or this node was not 
  622.  * created via hcl.
  623.  */
  624.                                 which_place++;
  625.                                 goto again;
  626.                         }
  627.                         if (name != NULL)
  628.                                 strcpy(name, HWGRAPH_EDGELBL_DOTDOT);
  629.                         if (target != NULL)
  630.                                 *target = connect_point;
  631.                 } else if (which_place == EDGE_PLACE_WANT_REAL_EDGES) {
  632. /* 
  633.  * return first "real" entry in directory, and increment
  634.  * placeptr.  Next time around we should have 
  635.  * which_place > HWGRAPH_RESERVED_EDGES so we'll fall through
  636.  * this nested if block.
  637.  */
  638. *target = devfs_get_first_child(source);
  639. if (*target && name) {
  640. tempname = devfs_get_name(*target, &namelen);
  641. if (tempname && namelen)
  642. strcpy(name, tempname);
  643. }
  644. *placeptr = which_place + 1;
  645. return (0);
  646.                 }
  647.                 *placeptr = which_place+1;
  648.                 return(0);
  649.         }
  650. /*
  651.  * walk linked list, (which_place - HWGRAPH_RESERVED_PLACES) times
  652.  */
  653. {
  654. devfs_handle_t curr;
  655. int i = 0;
  656. for (curr=devfs_get_first_child(source), i= i+HWGRAPH_RESERVED_PLACES; 
  657. curr!=NULL && i<which_place; 
  658. curr=devfs_get_next_sibling(curr), i++)
  659. ;
  660. *target = curr;
  661. *placeptr = which_place + 1;
  662. if (curr && name) {
  663. tempname = devfs_get_name(*target, &namelen);
  664. if (tempname && namelen)
  665. strcpy(name, tempname);
  666. }
  667. }
  668. if (target == NULL)
  669. return(-1);
  670. else
  671.          return(0);
  672. }
  673. /*
  674.  * hwgraph_info_add_LBL - Adds a new label for the device.  Mark the info_desc
  675.  * of the label as INFO_DESC_PRIVATE and store the info in the label.
  676.  */
  677. /* ARGSUSED */
  678. int
  679. hwgraph_info_add_LBL( devfs_handle_t de,
  680. char *name,
  681. arbitrary_info_t info)
  682. {
  683. return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info));
  684. }
  685. /*
  686.  * hwgraph_info_remove_LBL - Remove the label entry for the device.
  687.  */
  688. /* ARGSUSED */
  689. int
  690. hwgraph_info_remove_LBL( devfs_handle_t de,
  691. char *name,
  692. arbitrary_info_t *old_info)
  693. {
  694. return(labelcl_info_remove_LBL(de, name, NULL, old_info));
  695. }
  696. /*
  697.  * hwgraph_info_replace_LBL - replaces an existing label with 
  698.  * a new label info value.
  699.  */
  700. /* ARGSUSED */
  701. int
  702. hwgraph_info_replace_LBL( devfs_handle_t de,
  703. char *name,
  704. arbitrary_info_t info,
  705. arbitrary_info_t *old_info)
  706. {
  707. return(labelcl_info_replace_LBL(de, name,
  708. INFO_DESC_PRIVATE, info,
  709. NULL, old_info));
  710. }
  711. /*
  712.  * hwgraph_info_get_LBL - Get and return the info value in the label of the 
  713.  *  device.
  714.  */
  715. /* ARGSUSED */
  716. int
  717. hwgraph_info_get_LBL( devfs_handle_t de,
  718. char *name,
  719. arbitrary_info_t *infop)
  720. {
  721. return(labelcl_info_get_LBL(de, name, NULL, infop));
  722. }
  723. /*
  724.  * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer 
  725.  * of the given label for the device.  The weird thing is that the label 
  726.  * that matches the name is return irrespective of the info_desc value!
  727.  * Do not understand why the word "exported" is used!
  728.  */
  729. /* ARGSUSED */
  730. int
  731. hwgraph_info_get_exported_LBL( devfs_handle_t de,
  732. char *name,
  733. int *export_info,
  734. arbitrary_info_t *infop)
  735. {
  736. int rc;
  737. arb_info_desc_t info_desc;
  738. rc = labelcl_info_get_LBL(de, name, &info_desc, infop);
  739. if (rc == 0)
  740. *export_info = (int)info_desc;
  741. return(rc);
  742. }
  743. /*
  744.  * hwgraph_info_get_next_LBL - Returns the next label info given the 
  745.  * current label entry in place.
  746.  *
  747.  * Once again this has no locking or reference count for protection.
  748.  *
  749.  */
  750. /* ARGSUSED */
  751. int
  752. hwgraph_info_get_next_LBL( devfs_handle_t de,
  753. char *buf,
  754. arbitrary_info_t *infop,
  755. labelcl_info_place_t *place)
  756. {
  757. return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place));
  758. }
  759. /*
  760.  * hwgraph_info_export_LBL - Retrieve the specified label entry and modify 
  761.  * the info_desc field with the given value in nbytes.
  762.  */
  763. /* ARGSUSED */
  764. int
  765. hwgraph_info_export_LBL(devfs_handle_t de, char *name, int nbytes)
  766. {
  767. arbitrary_info_t info;
  768. int rc;
  769. if (nbytes == 0)
  770. nbytes = INFO_DESC_EXPORT;
  771. if (nbytes < 0)
  772. return(-1);
  773. rc = labelcl_info_get_LBL(de, name, NULL, &info);
  774. if (rc != 0)
  775. return(rc);
  776. rc = labelcl_info_replace_LBL(de, name,
  777. nbytes, info, NULL, NULL);
  778. return(rc);
  779. }
  780. /*
  781.  * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the 
  782.  * label info_descr filed to INFO_DESC_PRIVATE.
  783.  */
  784. /* ARGSUSED */
  785. int
  786. hwgraph_info_unexport_LBL(devfs_handle_t de, char *name)
  787. {
  788. arbitrary_info_t info;
  789. int rc;
  790. rc = labelcl_info_get_LBL(de, name, NULL, &info);
  791. if (rc != 0)
  792. return(rc);
  793. rc = labelcl_info_replace_LBL(de, name,
  794. INFO_DESC_PRIVATE, info, NULL, NULL);
  795. return(rc);
  796. }
  797. /*
  798.  * hwgraph_path_lookup - return the handle for the given path.
  799.  *
  800.  */
  801. int
  802. hwgraph_path_lookup( devfs_handle_t start_vertex_handle,
  803. char *lookup_path,
  804. devfs_handle_t *vertex_handle_ptr,
  805. char **remainder)
  806. {
  807. *vertex_handle_ptr = devfs_find_handle(start_vertex_handle, /* start dir */
  808. lookup_path, /* path */
  809. 0, /* major */
  810. 0, /* minor */
  811. 0, /* char | block */
  812. 1); /* traverse symlinks */
  813. if (*vertex_handle_ptr == NULL)
  814. return(-1);
  815. else
  816. return(0);
  817. }
  818. /*
  819.  * hwgraph_traverse - Find and return the devfs handle starting from de.
  820.  *
  821.  */
  822. graph_error_t
  823. hwgraph_traverse(devfs_handle_t de, char *path, devfs_handle_t *found)
  824. {
  825. /* 
  826.  * get the directory entry (path should end in a directory)
  827.  */
  828. *found = devfs_find_handle(de, /* start dir */
  829.     path, /* path */
  830.     0, /* major */
  831.     0, /* minor */
  832.     0, /* char | block */
  833.     1); /* traverse symlinks */
  834. if (*found == NULL)
  835. return(GRAPH_NOT_FOUND);
  836. else
  837. return(GRAPH_SUCCESS);
  838. }
  839. /*
  840.  * hwgraph_path_to_vertex - Return the devfs entry handle for the given 
  841.  * pathname .. assume traverse symlinks too!.
  842.  */
  843. devfs_handle_t
  844. hwgraph_path_to_vertex(char *path)
  845. {
  846. return(devfs_find_handle(NULL, /* start dir */
  847. path, /* path */
  848.      0, /* major */
  849.      0, /* minor */
  850.      0, /* char | block */
  851.      1)); /* traverse symlinks */
  852. }
  853. /*
  854.  * hwgraph_path_to_dev - Returns the devfs_handle_t of the given path ..
  855.  * We only deal with devfs handle and not devfs_handle_t.
  856. */
  857. devfs_handle_t
  858. hwgraph_path_to_dev(char *path)
  859. {
  860. devfs_handle_t  de;
  861. de = hwgraph_path_to_vertex(path);
  862. return(de);
  863. }
  864. /*
  865.  * hwgraph_block_device_get - return the handle of the block device file.
  866.  * The assumption here is that de is a directory.
  867. */
  868. devfs_handle_t
  869. hwgraph_block_device_get(devfs_handle_t de)
  870. {
  871. return(devfs_find_handle(de, /* start dir */
  872. "block", /* path */
  873.      0, /* major */
  874.      0, /* minor */
  875.      DEVFS_SPECIAL_BLK, /* char | block */
  876.      1)); /* traverse symlinks */
  877. }
  878. /*
  879.  * hwgraph_char_device_get - return the handle of the char device file.
  880.  *      The assumption here is that de is a directory.
  881. */
  882. devfs_handle_t
  883. hwgraph_char_device_get(devfs_handle_t de)
  884. {
  885. return(devfs_find_handle(de, /* start dir */
  886. "char", /* path */
  887.      0, /* major */
  888.      0, /* minor */
  889.      DEVFS_SPECIAL_CHR, /* char | block */
  890.      1)); /* traverse symlinks */
  891. }
  892. /*
  893. ** Inventory is now associated with a vertex in the graph.  For items that
  894. ** belong in the inventory but have no vertex 
  895. ** (e.g. old non-graph-aware drivers), we create a bogus vertex under the 
  896. ** INFO_LBL_INVENT name.
  897. **
  898. ** For historical reasons, we prevent exact duplicate entries from being added
  899. ** to a single vertex.
  900. */
  901. /*
  902.  * hwgraph_inventory_add - Adds an inventory entry into de.
  903.  */
  904. int
  905. hwgraph_inventory_add( devfs_handle_t de,
  906. int class,
  907. int type,
  908. major_t controller,
  909. minor_t unit,
  910. int state)
  911. {
  912. inventory_t *pinv = NULL, *old_pinv = NULL, *last_pinv = NULL;
  913. int rv;
  914. /*
  915.  * Add our inventory data to the list of inventory data
  916.  * associated with this vertex.
  917.  */
  918. again:
  919. /* GRAPH_LOCK_UPDATE(&invent_lock); */
  920. rv = labelcl_info_get_LBL(de,
  921. INFO_LBL_INVENT,
  922. NULL, (arbitrary_info_t *)&old_pinv);
  923. if ((rv != LABELCL_SUCCESS) && (rv != LABELCL_NOT_FOUND))
  924. goto failure;
  925. /*
  926.  * Seek to end of inventory items associated with this
  927.  * vertex.  Along the way, make sure we're not duplicating
  928.  * an inventory item (for compatibility with old add_to_inventory)
  929.  */
  930. for (;old_pinv; last_pinv = old_pinv, old_pinv = old_pinv->inv_next) {
  931. if ((int)class != -1 && old_pinv->inv_class != class)
  932. continue;
  933. if ((int)type != -1 && old_pinv->inv_type != type)
  934. continue;
  935. if ((int)state != -1 && old_pinv->inv_state != state)
  936. continue;
  937. if ((int)controller != -1
  938.     && old_pinv->inv_controller != controller)
  939. continue;
  940. if ((int)unit != -1 && old_pinv->inv_unit != unit)
  941. continue;
  942. /* exact duplicate of previously-added inventory item */
  943. rv = LABELCL_DUP;
  944. goto failure;
  945. }
  946. /* Not a duplicate, so we know that we need to add something. */
  947. if (pinv == NULL) {
  948. /* Release lock while we wait for memory. */
  949. /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
  950. pinv = (inventory_t *)kmalloc(sizeof(inventory_t), GFP_KERNEL);
  951. replace_in_inventory(pinv, class, type, controller, unit, state);
  952. goto again;
  953. }
  954. pinv->inv_next = NULL;
  955. if (last_pinv) {
  956. last_pinv->inv_next = pinv;
  957. } else {
  958. rv = labelcl_info_add_LBL(de, INFO_LBL_INVENT, 
  959. sizeof(inventory_t), (arbitrary_info_t)pinv);
  960. if (!rv)
  961. goto failure;
  962. }
  963. /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
  964. return(0);
  965. failure:
  966. /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
  967. if (pinv)
  968. kfree(pinv);
  969. return(rv);
  970. }
  971. /*
  972.  * hwgraph_inventory_remove - Removes an inventory entry.
  973.  *
  974.  * Remove an inventory item associated with a vertex.   It is the caller's
  975.  * responsibility to make sure that there are no races between removing
  976.  * inventory from a vertex and simultaneously removing that vertex.
  977. */
  978. int
  979. hwgraph_inventory_remove( devfs_handle_t de,
  980. int class,
  981. int type,
  982. major_t controller,
  983. minor_t unit,
  984. int state)
  985. {
  986. inventory_t *pinv = NULL, *last_pinv = NULL, *next_pinv = NULL;
  987. labelcl_error_t rv;
  988. /*
  989.  * We never remove stuff from ".invent" ..
  990.  */
  991. if (!de)
  992. return (-1);
  993. /*
  994.  * Remove our inventory data to the list of inventory data
  995.  * associated with this vertex.
  996.  */
  997. /* GRAPH_LOCK_UPDATE(&invent_lock); */
  998. rv = labelcl_info_get_LBL(de,
  999. INFO_LBL_INVENT,
  1000. NULL, (arbitrary_info_t *)&pinv);
  1001. if (rv != LABELCL_SUCCESS)
  1002. goto failure;
  1003. /*
  1004.  * Search through inventory items associated with this
  1005.  * vertex, looking for a match.
  1006.  */
  1007. for (;pinv; pinv = next_pinv) {
  1008. next_pinv = pinv->inv_next;
  1009. if(((int)class == -1 || pinv->inv_class == class) &&
  1010.    ((int)type == -1 || pinv->inv_type == type) &&
  1011.    ((int)state == -1 || pinv->inv_state == state) &&
  1012.    ((int)controller == -1 || pinv->inv_controller == controller) &&
  1013.    ((int)unit == -1 || pinv->inv_unit == unit)) {
  1014. /* Found a matching inventory item. Remove it. */
  1015. if (last_pinv) {
  1016. last_pinv->inv_next = pinv->inv_next;
  1017. } else {
  1018. rv = hwgraph_info_replace_LBL(de, INFO_LBL_INVENT, (arbitrary_info_t)pinv->inv_next, NULL);
  1019. if (rv != LABELCL_SUCCESS)
  1020. goto failure;
  1021. }
  1022. pinv->inv_next = NULL; /* sanity */
  1023. kfree(pinv);
  1024. } else
  1025. last_pinv = pinv;
  1026. }
  1027. if (last_pinv == NULL) {
  1028. rv = hwgraph_info_remove_LBL(de, INFO_LBL_INVENT, NULL);
  1029. if (rv != LABELCL_SUCCESS)
  1030. goto failure;
  1031. }
  1032. rv = LABELCL_SUCCESS;
  1033. failure:
  1034. /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */
  1035. return(rv);
  1036. }
  1037. /*
  1038.  * hwgraph_inventory_get_next - Get next inventory item associated with the 
  1039.  * specified vertex.
  1040.  *
  1041.  * No locking is really needed.  We don't yet have the ability
  1042.  * to remove inventory items, and new items are always added to
  1043.  * the end of a vertex' inventory list.
  1044.  *
  1045.  *  However, a devfs entry can be removed!
  1046. */
  1047. int
  1048. hwgraph_inventory_get_next(devfs_handle_t de, invplace_t *place, inventory_t **ppinv)
  1049. {
  1050. inventory_t *pinv;
  1051. labelcl_error_t rv;
  1052. if (de == NULL)
  1053. return(LABELCL_BAD_PARAM);
  1054. if (place->invplace_vhdl == NULL) {
  1055. place->invplace_vhdl = de;
  1056. place->invplace_inv = NULL;
  1057. }
  1058. if (de != place->invplace_vhdl)
  1059. return(LABELCL_BAD_PARAM);
  1060. if (place->invplace_inv == NULL) {
  1061. /* Just starting on this vertex */
  1062. rv = labelcl_info_get_LBL(de, INFO_LBL_INVENT,
  1063. NULL, (arbitrary_info_t *)&pinv);
  1064. if (rv != LABELCL_SUCCESS)
  1065. return(LABELCL_NOT_FOUND);
  1066. } else {
  1067. /* Advance to next item on this vertex */
  1068. pinv = place->invplace_inv->inv_next;
  1069. }
  1070. place->invplace_inv = pinv;
  1071. *ppinv = pinv;
  1072. return(LABELCL_SUCCESS);
  1073. }
  1074. /*
  1075.  * hwgraph_controller_num_get - Returns the controller number in the inventory 
  1076.  * entry.
  1077.  */
  1078. int
  1079. hwgraph_controller_num_get(devfs_handle_t device)
  1080. {
  1081. inventory_t *pinv;
  1082. invplace_t invplace = { NULL, NULL, NULL };
  1083. int val = -1;
  1084. if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) {
  1085. val = (pinv->inv_class == INV_NETWORK)? pinv->inv_unit: pinv->inv_controller;
  1086. }
  1087. #ifdef DEBUG
  1088. /*
  1089.  * It does not make any sense to call this on vertexes with multiple
  1090.  * inventory structs chained together
  1091.  */
  1092. if ( device_inventory_get_next(device, &invplace) != NULL ) {
  1093. printk("Should panic here ... !n");
  1094. #endif
  1095. return (val);
  1096. }
  1097. /*
  1098.  * hwgraph_controller_num_set - Sets the controller number in the inventory 
  1099.  * entry.
  1100.  */
  1101. void
  1102. hwgraph_controller_num_set(devfs_handle_t device, int contr_num)
  1103. {
  1104. inventory_t *pinv;
  1105. invplace_t invplace = { NULL, NULL, NULL };
  1106. if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) {
  1107. if (pinv->inv_class == INV_NETWORK)
  1108. pinv->inv_unit = contr_num;
  1109. else {
  1110. if (pinv->inv_class == INV_FCNODE)
  1111. pinv = device_inventory_get_next(device, &invplace);
  1112. if (pinv != NULL)
  1113. pinv->inv_controller = contr_num;
  1114. }
  1115. }
  1116. #ifdef DEBUG
  1117. /*
  1118.  * It does not make any sense to call this on vertexes with multiple
  1119.  * inventory structs chained together
  1120.  */
  1121. if(pinv != NULL)
  1122. ASSERT(device_inventory_get_next(device, &invplace) == NULL);
  1123. #endif
  1124. }
  1125. /*
  1126.  * Find the canonical name for a given vertex by walking back through
  1127.  * connectpt's until we hit the hwgraph root vertex (or until we run
  1128.  * out of buffer space or until something goes wrong).
  1129.  *
  1130.  * COMPATIBILITY FUNCTIONALITY
  1131.  * Walks back through 'parents', not necessarily the same as connectpts.
  1132.  *
  1133.  * Need to resolve the fact that devfs does not return the path from 
  1134.  * "/" but rather it just stops right before /dev ..
  1135.  */
  1136. int
  1137. hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen)
  1138. {
  1139. char *locbuf;
  1140. int   pos;
  1141. if (buflen < 1)
  1142. return(-1); /* XXX should be GRAPH_BAD_PARAM ? */
  1143. locbuf = kmalloc(buflen, GFP_KERNEL);
  1144. pos = devfs_generate_path(vhdl, locbuf, buflen);
  1145. if (pos < 0) {
  1146. kfree(locbuf);
  1147. return pos;
  1148. }
  1149. strcpy(buf, &locbuf[pos]);
  1150. kfree(locbuf);
  1151. return 0;
  1152. }
  1153. /*
  1154. ** vertex_to_name converts a vertex into a canonical name by walking
  1155. ** back through connect points until we hit the hwgraph root (or until
  1156. ** we run out of buffer space).
  1157. **
  1158. ** Usually returns a pointer to the original buffer, filled in as
  1159. ** appropriate.  If the buffer is too small to hold the entire name,
  1160. ** or if anything goes wrong while determining the name, vertex_to_name
  1161. ** returns "UnknownDevice".
  1162. */
  1163. #define DEVNAME_UNKNOWN "UnknownDevice"
  1164. char *
  1165. vertex_to_name(devfs_handle_t vhdl, char *buf, uint buflen)
  1166. {
  1167. if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS)
  1168. return(buf);
  1169. else
  1170. return(DEVNAME_UNKNOWN);
  1171. }
  1172. #ifdef LATER
  1173. /*
  1174. ** Return the compact node id of the node that ultimately "owns" the specified
  1175. ** vertex.  In order to do this, we walk back through masters and connect points
  1176. ** until we reach a vertex that represents a node.
  1177. */
  1178. cnodeid_t
  1179. master_node_get(devfs_handle_t vhdl)
  1180. {
  1181. cnodeid_t cnodeid;
  1182. devfs_handle_t master;
  1183. for (;;) {
  1184. cnodeid = nodevertex_to_cnodeid(vhdl);
  1185. if (cnodeid != CNODEID_NONE)
  1186. return(cnodeid);
  1187. master = device_master_get(vhdl);
  1188. /* Check for exceptional cases */
  1189. if (master == vhdl) {
  1190. /* Since we got a reference to the "master" thru
  1191.  * device_master_get() we should decrement
  1192.  * its reference count by 1
  1193.  */
  1194. hwgraph_vertex_unref(master);
  1195. return(CNODEID_NONE);
  1196. }
  1197. if (master == GRAPH_VERTEX_NONE) {
  1198. master = hwgraph_connectpt_get(vhdl);
  1199. if ((master == GRAPH_VERTEX_NONE) ||
  1200.     (master == vhdl)) {
  1201. if (master == vhdl)
  1202. /* Since we got a reference to the
  1203.  * "master" thru
  1204.  * hwgraph_connectpt_get() we should
  1205.  * decrement its reference count by 1
  1206.  */
  1207. hwgraph_vertex_unref(master);
  1208. return(CNODEID_NONE);
  1209. }
  1210. }
  1211. vhdl = master;
  1212. /* Decrement the reference to "master" which was got
  1213.  * either thru device_master_get() or hwgraph_connectpt_get()
  1214.  * above.
  1215.  */
  1216. hwgraph_vertex_unref(master);
  1217. }
  1218. }
  1219. /*
  1220.  * Using the canonical path name to get hold of the desired vertex handle will
  1221.  * not work on multi-hub sn0 nodes. Hence, we use the following (slightly
  1222.  * convoluted) algorithm.
  1223.  *
  1224.  * - Start at the vertex corresponding to the driver (provided as input parameter)
  1225.  * - Loop till you reach a vertex which has EDGE_LBL_MEMORY
  1226.  *    - If EDGE_LBL_CONN exists, follow that up.
  1227.  *      else if EDGE_LBL_MASTER exists, follow that up.
  1228.  *      else follow EDGE_LBL_DOTDOT up.
  1229.  *
  1230.  * * We should be at desired hub/heart vertex now *
  1231.  * - Follow EDGE_LBL_CONN to the widget vertex.
  1232.  *
  1233.  * - return vertex handle of this widget.
  1234.  */
  1235. devfs_handle_t
  1236. mem_vhdl_get(devfs_handle_t drv_vhdl)
  1237. {
  1238. devfs_handle_t cur_vhdl, cur_upper_vhdl;
  1239. devfs_handle_t tmp_mem_vhdl, mem_vhdl;
  1240. graph_error_t loop_rv;
  1241.   /* Initializations */
  1242.   cur_vhdl = drv_vhdl;
  1243.   loop_rv = ~GRAPH_SUCCESS;
  1244.   /* Loop till current vertex has EDGE_LBL_MEMORY */
  1245.   while (loop_rv != GRAPH_SUCCESS) {
  1246.     if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &cur_upper_vhdl)) == GRAPH_SUCCESS) {
  1247.     } else if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_MASTER, &cur_upper_vhdl)) == GRAPH_SUCCESS) {
  1248.       } else { /* Follow HWGRAPH_EDGELBL_DOTDOT up */
  1249.            (void) hwgraph_edge_get(cur_vhdl, HWGRAPH_EDGELBL_DOTDOT, &cur_upper_vhdl);
  1250.         }
  1251.     cur_vhdl = cur_upper_vhdl;
  1252. #if DEBUG && HWG_DEBUG
  1253.     printf("Current vhdl %d n", cur_vhdl);
  1254. #endif /* DEBUG */
  1255.     loop_rv = hwgraph_edge_get(cur_vhdl, EDGE_LBL_MEMORY, &tmp_mem_vhdl);
  1256.   }
  1257.   /* We should be at desired hub/heart vertex now */
  1258.   if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &mem_vhdl)) != GRAPH_SUCCESS)
  1259.     return (GRAPH_VERTEX_NONE);
  1260.   return (mem_vhdl);
  1261. }
  1262. #endif /* LATER */
  1263. /*
  1264. ** Add a char device -- if the driver supports it -- at a specified vertex.
  1265. */
  1266. graph_error_t
  1267. hwgraph_char_device_add(        devfs_handle_t from,
  1268.                                 char *path,
  1269.                                 char *prefix,
  1270.                                 devfs_handle_t *devhdl)
  1271. {
  1272. devfs_handle_t xx = NULL;
  1273. printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.n");
  1274. *devhdl = xx; // Must set devhdl
  1275. return(GRAPH_SUCCESS);
  1276. }
  1277. graph_error_t
  1278. hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr)
  1279. {
  1280. printk("WARNING: hwgraph_edge_remove NOT supported.n");
  1281. return(GRAPH_ILLEGAL_REQUEST);
  1282. }
  1283. graph_error_t
  1284. hwgraph_vertex_unref(devfs_handle_t vhdl)
  1285. {
  1286. return(GRAPH_ILLEGAL_REQUEST);
  1287. }
  1288. EXPORT_SYMBOL(hwgraph_mk_dir);
  1289. EXPORT_SYMBOL(hwgraph_path_add);
  1290. EXPORT_SYMBOL(hwgraph_char_device_add);
  1291. EXPORT_SYMBOL(hwgraph_register);
  1292. EXPORT_SYMBOL(hwgraph_vertex_destroy);
  1293. EXPORT_SYMBOL(hwgraph_fastinfo_get);
  1294. EXPORT_SYMBOL(hwgraph_edge_get);
  1295. EXPORT_SYMBOL(hwgraph_fastinfo_set);
  1296. EXPORT_SYMBOL(hwgraph_connectpt_set);
  1297. EXPORT_SYMBOL(hwgraph_connectpt_get);
  1298. EXPORT_SYMBOL(hwgraph_edge_get_next);
  1299. EXPORT_SYMBOL(hwgraph_info_add_LBL);
  1300. EXPORT_SYMBOL(hwgraph_info_remove_LBL);
  1301. EXPORT_SYMBOL(hwgraph_info_replace_LBL);
  1302. EXPORT_SYMBOL(hwgraph_info_get_LBL);
  1303. EXPORT_SYMBOL(hwgraph_info_get_exported_LBL);
  1304. EXPORT_SYMBOL(hwgraph_info_get_next_LBL);
  1305. EXPORT_SYMBOL(hwgraph_info_export_LBL);
  1306. EXPORT_SYMBOL(hwgraph_info_unexport_LBL);
  1307. EXPORT_SYMBOL(hwgraph_path_lookup);
  1308. EXPORT_SYMBOL(hwgraph_traverse);
  1309. EXPORT_SYMBOL(hwgraph_path_to_vertex);
  1310. EXPORT_SYMBOL(hwgraph_path_to_dev);
  1311. EXPORT_SYMBOL(hwgraph_block_device_get);
  1312. EXPORT_SYMBOL(hwgraph_char_device_get);
  1313. EXPORT_SYMBOL(hwgraph_vertex_name_get);