/*
* 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
*/
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <door.h>
#include <libnvpair.h>
#include <libhotplug.h>
#include <libhotplug_impl.h>
static void i_hp_dprintf(const char *fmt, ...);
const char *, int, uint32_t);
/*
* Global flag to enable debug features.
*/
int libhotplug_debug = 0;
/*
* hp_init()
*
* Initialize a hotplug information snapshot.
*/
{
int rv;
i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n",
/* Check arguments */
i_hp_dprintf("hp_init: invalid arguments.\n");
return (NULL);
}
/* Build arguments for door call */
i_hp_dprintf("hp_init: cannot build arguments nvlist.\n");
return (NULL);
}
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Check for errors */
if (rv != 0) {
if (root)
return (NULL);
}
/* Success requires an info snapshot */
i_hp_dprintf("hp_init: missing info snapshot.\n");
return (NULL);
}
/* Success */
return (root);
}
/*
* hp_fini()
*
* Terminate and clean-up a hotplug information snapshot.
*/
void
{
char *basepath;
i_hp_dprintf("hp_fini: invalid arguments.\n");
return;
}
/* Extract and free base path */
if (root->hp_basepath) {
}
/* Destroy the nodes */
while (node) {
if (node->hp_description)
if (node->hp_state_priv)
}
}
/*
* hp_traverse()
*
* Walk a graph of hotplug nodes, executing a callback on each node.
*/
int
{
int rv;
i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
/* Check arguments */
i_hp_dprintf("hp_traverse: invalid arguments.\n");
return (-1);
}
if (rv == HP_WALK_TERMINATE) {
i_hp_dprintf("hp_traverse: walk terminated.\n");
return (HP_WALK_TERMINATE);
}
i_hp_dprintf("hp_traverse: walk terminated.\n");
return (HP_WALK_TERMINATE);
}
if (rv == HP_WALK_PRUNESIBLING)
break;
}
return (0);
}
/*
* hp_type()
*
* Return a node's type.
*/
int
{
i_hp_dprintf("hp_type: invalid arguments.\n");
return (-1);
}
}
/*
* hp_name()
*
* Return a node's name.
*/
char *
{
i_hp_dprintf("hp_name: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_name: missing name value.\n");
}
}
/*
* hp_state()
*
* Return a node's current state.
*/
int
{
i_hp_dprintf("hp_state: invalid arguments.\n");
return (-1);
}
i_hp_dprintf("hp_state: operation not supported.\n");
return (-1);
}
}
/*
* hp_state_priv()
*
* Return a node's state private info.
*/
char *
{
i_hp_dprintf("hp_state_priv: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_state_priv: operation not supported.\n");
return (NULL);
}
i_hp_dprintf("hp_state_priv: "
"node has no state private info.\n");
}
return (node->hp_state_priv);
}
/*
* hp_usage()
*
* Return a usage description for usage nodes.
*/
char *
{
i_hp_dprintf("hp_usage: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_usage: operation not supported.\n");
return (NULL);
}
i_hp_dprintf("hp_usage: missing usage value.\n");
}
}
/*
* hp_description()
*
* Return a type description (e.g. "PCI slot") for connection nodes.
*/
char *
{
i_hp_dprintf("hp_description: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_description: operation not supported.\n");
return (NULL);
}
i_hp_dprintf("hp_description: missing description value.\n");
}
return (node->hp_description);
}
/*
* hp_driver()
*
* Return the driver name of a device node.
*/
char *
{
i_hp_dprintf("hp_driver: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_driver: operation not supported.\n");
return (NULL);
}
i_hp_dprintf("hp_driver: missing driver value.\n");
}
}
/*
* hp_instance()
*
* Return the instance number of a device node.
*/
int
{
i_hp_dprintf("hp_intance: invalid arguments.\n");
return (-1);
}
i_hp_dprintf("hp_instance: operation not supported.\n");
return (-1);
}
return (node->hp_instance);
}
/*
* hp_last_change()
*
* Return when the state of a connection was last changed.
*/
{
i_hp_dprintf("hp_last_change: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_last_change: operation not supported.\n");
return (NULL);
}
return (node->hp_last_change);
}
/*
* hp_parent()
*
* Return a node's parent node.
*/
{
i_hp_dprintf("hp_parent: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_parent: node has no parent.\n");
}
}
/*
* hp_child()
*
* Return a node's first child node.
*/
{
i_hp_dprintf("hp_child: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_child: node has no child.\n");
}
}
/*
* hp_sibling()
*
* Return a node's next sibling node.
*/
{
i_hp_dprintf("hp_sibling: invalid arguments.\n");
return (NULL);
}
i_hp_dprintf("hp_sibling: node has no sibling.\n");
}
return (node->hp_sibling);
}
/*
* hp_path()
*
* Return the path (and maybe connection name) of a node.
* The caller must supply two buffers, each MAXPATHLEN size.
*/
int
{
int i;
char *s;
(void *)path, (void *)connection);
i_hp_dprintf("hp_path: invalid arguments.\n");
return (EINVAL);
}
/* Set 'connection' only for connectors and ports */
/* Trace back to the root node, accumulating components */
}
}
/* Ensure the snapshot actually contains a base path */
i_hp_dprintf("hp_path: missing base pathname.\n");
return (EFAULT);
}
/*
* Construct the path. Start with the base path from the root
* node, then append the accumulated components in reverse order.
*/
*s = '\0';
} else {
/* Remove the rootnex component, the '/' and its name */
*s = '\0';
/*
* For special case that @node is the root of the snapshot,
* and itself is the rootnex or the port under the rootnex,
* components[] is an empty string, restore it to be "/".
* This step will not restore its name.
*/
if (components[0] == '\0')
}
if (components[i] == '/') {
components[i] = '\0';
}
}
return (0);
}
/*
* hp_state_ceiling()
*
* Return a node's current state ceiling.
*/
int
{
i_hp_dprintf("hp_state_ceiling: node=%p, name=%s, state=%x, "
i_hp_dprintf("hp_state_ceiling: invalid arguments.\n");
return (-1);
}
i_hp_dprintf("hp_state_ceiling: operation not supported.\n");
return (-1);
}
/* No state ceiling set */
i_hp_dprintf("hp_state_ceiling: no ceiling set.\n");
return (-1);
}
return (node->hp_state_ceiling);
}
/*
* hp_set_state_ceiling()
*
* Set a state ceiling on a hotplug connection.
*/
int
{
int rv;
i_hp_dprintf("hp_set_state_ceiling: node=%p, state=0x%x, "
/* Check arguments */
i_hp_dprintf("hp_set_state_ceiling: invalid arguments.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_set_state_ceiling: operation not "
"supported.\n");
return (ENOTSUP);
}
/* Check that target state ceiling is valid */
if (state != DDI_HP_CN_STATE_OFFLINE) {
i_hp_dprintf("hp_set_state_ceiling: not supported target"
" ceiling.\n");
return (ENOTSUP);
}
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
/* Parse additional results, if any */
/* Parse handle */
*handlep = 0;
i_hp_dprintf("i_hp_call_hotplugd: missing handle.\n");
}
}
/* Done */
return (rv);
}
/*
* hp_clear_state_ceiling()
*
* Clear a state ceiling on a node.
*/
int
{
int rv;
i_hp_dprintf("hp_clear_state_ceiling: node=%p, handle=%x, "
/* Check arguments */
i_hp_dprintf("hp_clear_state_ceiling: invalid arguments.\n");
return (EINVAL);
}
i_hp_dprintf("hp_clear_state_ceiling: no handle or "
"force flag.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_clear_state_ceiling: "
"operation not supported.\n");
return (ENOTSUP);
}
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Done */
return (rv);
}
/*
* hp_set_state()
*
* Initiate a state change operation on a node.
*/
int
{
int rv;
i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
/* Check arguments */
i_hp_dprintf("hp_set_state: invalid arguments.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_set_state: operation not supported.\n");
return (ENOTSUP);
}
/* Check that target state is valid */
switch (state) {
case DDI_HP_CN_STATE_PRESENT:
case DDI_HP_CN_STATE_POWERED:
case DDI_HP_CN_STATE_ENABLED:
i_hp_dprintf("hp_set_state: mismatched target.\n");
return (ENOTSUP);
}
break;
case DDI_HP_CN_STATE_OFFLINE:
case DDI_HP_CN_STATE_ONLINE:
i_hp_dprintf("hp_set_state: mismatched target.\n");
return (ENOTSUP);
}
break;
default:
i_hp_dprintf("hp_set_state: invalid target state.\n");
return (EINVAL);
}
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Done */
return (rv);
}
/*
* hp_set_private()
*
* Set bus private options on the hotplug connection
* indicated by the given hotplug information node.
*/
int
{
int rv;
i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
/* Check arguments */
i_hp_dprintf("hp_set_private: invalid arguments.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_set_private: operation not supported.\n");
return (ENOTSUP);
}
/* Initialize results */
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Done */
return (rv);
}
/*
* hp_get_private()
*
* Get bus private options on the hotplug connection
* indicated by the given hotplug information node.
*/
int
{
int rv;
i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
/* Check arguments */
i_hp_dprintf("hp_get_private: invalid arguments.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_get_private: operation not supported.\n");
return (ENOTSUP);
}
/* Initialize results */
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Done */
return (rv);
}
/*
* hp_install()
*
* Probe the dependencies of the given hotplug information node.
*/
int
{
int rv;
i_hp_dprintf("hp_install: node=%p, flags=0x%x, resultsp=%p\n",
/* Check arguments */
i_hp_dprintf("hp_install: invalid arguments.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_install: operation not supported.\n");
return (ENOTSUP);
}
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Done */
return (rv);
}
/*
* hp_uninstall()
*
* Un-install the dependencies of the given hotplug information node.
*/
int
{
int rv;
i_hp_dprintf("hp_uninstall: node=%p, flags=0x%x, resultsp=%p\n",
/* Check arguments */
i_hp_dprintf("hp_uninstall: invalid arguments.\n");
return (EINVAL);
}
/* Check node type */
i_hp_dprintf("hp_uninstall: operation not supported.\n");
return (ENOTSUP);
}
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
/* Done */
return (rv);
}
int
{
int rv;
/* Check arguments */
i_hp_dprintf("hp_create_port: invalid arguments.\n");
return (EINVAL);
}
/* Get path of specified node, HP_NODE_DEVICE has no connection */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Initialize results */
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
return (rv);
}
int
{
int rv;
/* Check arguments */
i_hp_dprintf("hp_remove_port: invalid arguments.\n");
return (EINVAL);
}
/* Get path and connection of specified node */
return (rv);
/* Build arguments for door call */
return (ENOMEM);
/* Initialize results */
/* Make the door call to hotplugd */
/* Arguments no longer needed */
/* Parse additional results, if any */
}
return (rv);
}
/*
* hp_pack()
*
* Given the root of a hotplug information snapshot, pack
* it into a contiguous byte array so that it is suitable
* for network transport.
*/
int
{
char *buf;
int rv;
i_hp_dprintf("hp_pack: invalid arguments.\n");
return (EINVAL);
}
*lenp = 0;
if (nvlist_alloc(&nvl, 0, 0) != 0) {
i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
return (ENOMEM);
}
if (rv != 0) {
return (rv);
}
}
}
if (rv != 0) {
return (rv);
}
}
len = 0;
}
return (rv);
}
/*
* hp_unpack()
*
* Unpack a hotplug information snapshot for normal usage.
*/
int
{
int rv;
i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
i_hp_dprintf("hp_unpack: invalid arguments.\n");
return (EINVAL);
}
return (rv);
return (NULL);
}
char *val_string;
}
}
if (rv == 0) {
if (prev_root) {
} else {
}
}
}
if (rv != 0) {
if (basepath)
return (rv);
}
}
/* Store the base path in each root node */
if (basepath) {
}
return (0);
}
/*
* i_hp_dprintf()
*
* Print debug messages to stderr, but only when the debug flag
* (libhotplug_debug) is set.
*/
/*PRINTFLIKE1*/
static void
{
if (libhotplug_debug) {
}
}
/*
* i_hp_pack_branch()
*
* Pack an individual branch of a hotplug information snapshot.
*/
static int
{
char *buf;
int rv;
*lenp = 0;
/* Allocate an nvlist for this branch */
if (nvlist_alloc(&nvl, 0, 0) != 0)
return (ENOMEM);
/* Pack the root of the branch and add it to the nvlist */
}
if (rv != 0) {
return (rv);
}
/* Pack each subordinate branch, and add it to the nvlist */
}
if (rv != 0) {
return (rv);
}
}
/* Pack the resulting nvlist into a single buffer */
len = 0;
}
/* Free the nvlist */
return (rv);
}
/*
* i_hp_pack_node()
*
* Pack an individual node of a hotplug information snapshot.
*/
static int
{
int rv;
if (nvlist_alloc(&nvl, 0, 0) != 0)
return (ENOMEM);
goto fail;
goto fail;
goto fail;
if ((node->hp_description) &&
node->hp_description)) != 0))
goto fail;
goto fail;
goto fail;
goto fail;
if ((node->hp_state_priv) &&
node->hp_state_priv)) != 0))
goto fail;
node->hp_state_ceiling)) != 0)
goto fail;
if ((node->hp_last_change != 0) &&
node->hp_last_change)) != 0))
goto fail;
goto fail;
return (0);
fail:
*lenp = 0;
return (rv);
}
/*
* i_hp_unpack_branch()
*
* Unpack a branch of hotplug information nodes.
*/
static int
{
char *buf;
int rv;
/* Initialize results */
/* Unpack the nvlist for this branch */
return (rv);
/*
* Unpack the branch. The first item in the nvlist is
* always the root node. And zero or more subordinate
* branches may be packed afterward.
*/
len = 0;
/* Check that there is only one root node */
return (EFAULT);
}
if (rv != 0) {
return (rv);
}
if (rv != 0) {
return (rv);
}
if (prev_child) {
} else {
}
prev_child = child;
}
}
return (0);
}
/*
* i_hp_unpack_node()
*
* Unpack an individual hotplug information node.
*/
static int
{
char *val_string;
int rv = 0;
/* Initialize results */
/* Unpack node into an nvlist */
return (EINVAL);
/* Allocate the new node */
return (ENOMEM);
}
/* Iterate through nvlist, unpacking each field */
break;
}
== NULL) {
break;
}
break;
}
== NULL) {
break;
}
break;
}
} else {
i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
nvpair_name(nvp));
}
}
/* Unpacked nvlist no longer needed */
/* Check for errors */
if (rv != 0) {
return (rv);
}
/* Success */
return (0);
}
/*
* i_hp_call_hotplugd()
*
* Perform a door call to the hotplug daemon.
*/
static int
{
int door_fd;
int rv;
/* Initialize results */
/* Open door */
i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
return (EBADF);
}
/* Pack the nvlist of arguments */
i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
return (rv);
}
/* Set the door argument using the packed arguments */
/* Attempt the door call */
i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
return (rv);
}
/* The arguments are no longer needed */
/*
* If results are not in the original buffer provided,
* then check and process the new results buffer.
*/
/*
* First check that the buffer is valid. Then check for
* the simple case where a short result code was sent.
* The last case is a packed nvlist was returned, which
* needs to be unpacked.
*/
i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
i_hp_dprintf("i_hp_call_hotplugd: "
}
/* Unmap the results buffer */
/*
* In the case of a packed nvlist, notify the daemon
* that it can free the result buffer from its heap.
*/
}
}
return (rv);
}
/*
* i_hp_set_args()
*
* Construct an nvlist of arguments for a hotplugd door call.
*/
static nvlist_t *
{
/* Allocate a new nvlist */
return (NULL);
/* Add common arguments */
return (NULL);
}
/* Add connection, but only if defined */
return (NULL);
}
/* Add flags, but only if defined */
return (NULL);
}
/* Add handle, but only if defined */
if ((cmd == HP_CMD_CLEAR_CEILING) &&
return (NULL);
}
/* Add options, but only if defined */
return (NULL);
}
/* Add state, but only for CHANGESTATE command */
return (NULL);
}
return (args);
}
/*
* i_hp_parse_results()
*
* Parse out individual fields of an nvlist of results from
* a hotplugd door call.
*/
static int
{
int rv;
/* Parse an information snapshot */
if (rootp) {
return (rv);
}
}
/* Parse a bus private option string */
if (optionsp) {
char *str;
return (ENOMEM);
}
}
/* Parse result code of the operation */
i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");
return (EFAULT);
}
return (rv);
}