/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libdevinfo.h>
#include <libhotplug.h>
#include <libhotplug_impl.h>
#include "hotplugd_impl.h"
/*
* Define a list of hotplug nodes.
* (Only used within this module.)
*/
typedef struct {
/*
* Local functions.
*/
static int copy_devinfo(const char *, const char *, uint_t,
hp_node_t *);
hp_node_t *);
static char *base_path(const char *);
/*
* getinfo()
*
* Build a hotplug information snapshot. The path, connection,
* and flags indicate what information should be included.
*/
int
{
char *basepath;
int rv;
return (EINVAL);
/* Allocate the base path */
return (ENOMEM);
/* Copy in device and hotplug nodes from libdevinfo */
return (rv);
}
/* Check if there were no connections */
dprintf("getinfo: no hotplug connections.\n");
return (ENOENT);
}
/* Special case: exclude root nexus from snapshot */
}
/* Store a pointer to the base path in each root node */
/* Copy in usage information from RCM */
if (flags & HPINFOUSAGE) {
return (rv);
}
}
return (0);
}
/*
* copy_devinfo()
*
* Copy information about device and hotplug nodes from libdevinfo.
*
* When path is set to "/", the results need to be limited only to
* branches that contain hotplug information. An initial search
* is performed to mark which branches contain hotplug nodes.
*/
static int
{
int rv;
/* Get libdevinfo snapshot */
return (errno);
/* Do initial search pass, if required */
flags |= HPINFOSEARCH;
}
/*
* If a connection is specified, just copy immediate hotplug info.
* Else, copy the device tree normally.
*/
if (connection != NULL)
else
/* Destroy devinfo snapshot */
return (rv);
}
/*
* copy_devices()
*
* Copy a full branch of device nodes. Used by copy_devinfo() and
* copy_hotplug().
*/
static int
{
int rv = 0;
/* Initialize results */
/* Enforce search semantics */
return (0);
/* Allocate new node for current device */
return (ENOMEM);
/*
* If the device has hotplug nodes, then use copy_hotplug()
* instead to build the branch associated with current device.
*/
return (rv);
}
return (0);
}
/*
* The device does not have hotplug nodes. Use normal
* approach of iterating through its child device nodes.
*/
return (rv);
}
}
/* Done */
return (0);
}
/*
* copy_hotplug()
*
* Copy a full branch of hotplug nodes. Used by copy_devinfo()
* and copy_devices().
*
* If a connection is specified, the results are limited only
* to the branch associated with that specific connection.
*/
static int
{
/* Stop implementing the HPINFOSEARCH flag */
/* Clear lists of discovered ports and connections */
/*
* Scan virtual ports.
*
* If a connection is specified and it matches a virtual port,
* this will build the branch associated with that connection.
* Else, this will only build branches for virtual ports that
* are not associated with a physical connector.
*/
/* Ignore connectors */
continue;
/*
* Ignore ports associated with connectors, unless
* a specific connection is being sought.
*/
continue;
/* If a connection is specified, ignore non-matching ports */
if ((connection != NULL) &&
continue;
/* Create a new port node */
goto fail;
}
/* Add port node to connection list */
/* Add branch of child devices to port node */
goto fail;
}
/*
* Scan physical connectors.
*
* If a connection is specified, the results will be limited
* only to the branch associated with that connection.
*/
/* Ignore ports */
continue;
/* If a connection is specified, ignore non-matching ports */
if ((connection != NULL) &&
continue;
/* Create a new connector node */
goto fail;
}
/* Add connector node to connection list */
/* Add branches of associated port nodes */
/* Ignore irrelevant connections */
continue;
/* Add new port node to port list */
goto fail;
}
/* Add branch of child devices */
goto fail;
}
}
}
return (ENXIO);
return (0);
fail:
return (rv);
}
/*
* base_path()
*
* Normalize the base path of a hotplug information snapshot.
* The caller must free the string that is allocated.
*/
static char *
{
char *base_path;
else
return (base_path);
}
/*
* search_cb()
*
* Callback function used by di_walk_node() to search for branches
* of the libdevinfo snapshot that contain hotplug nodes.
*/
/*ARGSUSED*/
static int
{
return (DI_WALK_CONTINUE);
flags |= HPINFOSEARCH;
}
return (DI_WALK_CONTINUE);
}
/*
* check_search()
*
* Check if a device node was marked by an initial search pass.
*/
static int
{
if (flags & HPINFOSEARCH) {
if ((dev_flags & HPINFOSEARCH) == 0)
return (0);
}
return (1);
}
/*
* node_list_add()
*
* Utility function to append one node to a list of hotplug nodes.
*/
static void
{
else
}
/*
* new_device_node()
*
* Build a new hotplug node based on a specified devinfo node.
*/
static hp_node_t
{
log_err("Path too long for device node.\n");
return (NULL);
}
} else
}
return (node);
}
/*
* new_hotplug_node()
*
* Build a new hotplug node based on a specified devinfo hotplug node.
*/
static hp_node_t
{
char *s;
else
}
return (node);
}