pkgsrc/sysutils/hal/files/hald-netbsd/drvctl.c
2018-05-19 13:25:36 +00:00

311 lines
7.6 KiB
C

/***************************************************************************
*
* drvctl.c : NetBSD drvctl events
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Licensed under the Academic Free License version 2.1
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/drvctlio.h>
#include <sys/dkio.h>
#include <sys/stat.h>
#include <sys/drvctlio.h>
#include <glib.h>
#include "../osspec.h"
#include "../logger.h"
#include "../hald.h"
#include "../hald_dbus.h"
#include "../device_info.h"
#include "../util.h"
#include "osspec_netbsd.h"
#include "hotplug.h"
#include "devinfo.h"
#include "devinfo_storage.h"
#include "drvctl.h"
static gboolean drvctl_iochannel_data(GIOChannel *, GIOCondition, gpointer);
static void drvctl_dev_add(gchar *);
static void drvctl_dev_remove(gchar *);
static void drvctl_dev_branch(gchar *);
static int drvctl_fd;
static GIOChannel *drvctl_iochannel;
gboolean
drvctl_init(void)
{
drvctl_fd = open (DRVCTLDEV, O_RDWR);
if (drvctl_fd == -1) {
HAL_INFO (("open(%s, O_RDWR) failed: %s", DRVCTLDEV, strerror(errno)));
return FALSE;
}
drvctl_iochannel = g_io_channel_unix_new (drvctl_fd);
if (drvctl_iochannel == NULL) {
HAL_INFO (("g_io_channel_unix_new failed"));
return FALSE;
}
g_io_add_watch (drvctl_iochannel, G_IO_IN, drvctl_iochannel_data, NULL);
return TRUE;
}
void
drvctl_fini(void)
{
HAL_INFO (("drvctl_fini"));
}
static gboolean
drvctl_iochannel_data (GIOChannel *source,
GIOCondition condition,
gpointer user_data)
{
prop_dictionary_t ev;
const char *event, *device;
int res;
HAL_INFO (("drvctl_iochannel_data"));
res = prop_dictionary_recv_ioctl (drvctl_fd, DRVGETEVENT, &ev);
if (res) {
HAL_WARNING (("DRVGETEVENT failed: %s", strerror(errno)));
return FALSE;
}
if (!prop_dictionary_get_cstring_nocopy (ev, "event", &event)) {
HAL_WARNING (("DRVGETEVENT missing \"event\" parameter"));
goto done;
}
if (!prop_dictionary_get_cstring_nocopy (ev, "device", &device)) {
HAL_WARNING (("DRVGETEVENT missing \"device\" parameter"));
goto done;
}
HAL_INFO (("DRVGETEVENT event=%s device=%s", event, device));
if (strcmp (event, "device-attach") == 0) {
drvctl_dev_add (device);
} else {
drvctl_dev_remove (device);
}
done:
prop_object_release(ev);
return TRUE;
}
static void
drvctl_dev_add(gchar *name)
{
HalDevice *parent, *d;
gchar pdevnode[512];
if (drvctl_find_parent (name, pdevnode) == FALSE) {
HAL_INFO (("dev_add: name=%s orphan", name));
parent = NULL;
} else {
parent = hal_device_store_match_key_value_string (
hald_get_gdl(), "netbsd.device", pdevnode);
if (parent == NULL)
HAL_INFO (("dev_add: name=%s but netbsd.device=%s not found",name, pdevnode));
}
d = devinfo_add_node (parent, name);
if (d == NULL)
HAL_WARNING (("dev_add: couldn't add %s node (parent=%p)", name, parent));
hotplug_event_process_queue ();
}
static void
drvctl_dev_remove(gchar *name)
{
HAL_INFO (("dev_remove: %s", name));
devinfo_remove_branch (name, NULL);
hotplug_event_process_queue ();
}
static void
drvctl_dev_branch(gchar *name)
{
HAL_INFO (("branch_remove: %s", name));
devinfo_remove_branch (name, NULL);
hotplug_event_process_queue ();
}
int
drvctl_list(const gchar *name, struct devlistargs *laa)
{
size_t children;
/* HAL_INFO (("drvctl_list: %s", name)); */
memset (laa, 0, sizeof (*laa));
strlcpy (laa->l_devname, name, sizeof (laa->l_devname));
if (ioctl (drvctl_fd, DRVLISTDEV, laa) == -1) {
HAL_INFO (("DRVLISTDEV/1 failed: %s", strerror(errno)));
return -1;
}
children = laa->l_children;
/* HAL_INFO (("%s: found %d children", name, children)); */
if (children == 0)
return -1;
laa->l_childname = malloc (children * sizeof (laa->l_childname[0]));
if (laa->l_childname == NULL) {
HAL_INFO (("drvctl_list couldn't allocate %d children: %s\n", children, strerror(errno)));
return -1;
}
if (ioctl (drvctl_fd, DRVLISTDEV, laa) == -1) {
HAL_INFO (("DRVLISTDEV/2 failed: %s", strerror(errno)));
return -1;
}
if (children != laa->l_children)
HAL_WARNING (("DRVLISTDEV/3 expected %d children, got %d", children, laa->l_childname));
return 0;
}
gboolean
drvctl_find_device(const gchar *devnode, prop_dictionary_t *properties)
{
prop_dictionary_t command_dict;
prop_dictionary_t args_dict;
prop_dictionary_t results_dict;
int err;
command_dict = prop_dictionary_create ();
args_dict = prop_dictionary_create ();
prop_dictionary_set_cstring_nocopy (command_dict, "drvctl-command", "get-properties");
prop_dictionary_set_cstring_nocopy (args_dict, "device-name", devnode);
prop_dictionary_set (command_dict, "drvctl-arguments", args_dict);
prop_object_release (args_dict);
err = prop_dictionary_sendrecv_ioctl (command_dict, drvctl_fd,
DRVCTLCOMMAND, &results_dict);
prop_object_release (command_dict);
if (err)
return FALSE;
if (prop_dictionary_get_int8 (results_dict, "drvctl-error", &err) == false || err != 0) {
prop_object_release (results_dict);
return FALSE;
}
if (properties) {
prop_dictionary_t result_data;
result_data = prop_dictionary_get (results_dict, "drvctl-result-data");
if (result_data)
*properties = prop_dictionary_copy (result_data);
}
prop_object_release (results_dict);
return TRUE;
}
static gboolean
drvctl_find_device_with_child(const gchar *curnode, const gchar *devnode,
char *parent)
{
struct devlistargs laa;
u_int i;
if (drvctl_list (curnode, &laa) == -1)
return FALSE;
for (i = 0; i < laa.l_children; i++) {
if (strcmp (laa.l_childname[i], devnode) == 0) {
strlcpy(parent, curnode, 16);
free(laa.l_childname);
return TRUE;
}
if (drvctl_find_device_with_child (laa.l_childname[i], devnode, parent) == TRUE) {
free(laa.l_childname);
return TRUE;
}
}
if (laa.l_childname)
free(laa.l_childname);
HAL_INFO (("%s: couldn't find device with child %s", curnode, devnode));
return FALSE;
}
gboolean
drvctl_find_parent(const gchar *devnode, char *parent)
{
gboolean ret;
ret = drvctl_find_device_with_child("mainbus0", devnode, parent);
if (ret == FALSE) {
ret = drvctl_find_device_with_child("armfdt0", devnode, parent);
}
return ret;
}
#if 0
static void
drvctl_lofi_add(gchar *devfs_path, gchar *name)
{
di_node_t node;
const char *parent_udi;
HalDevice *d, *parent;
HAL_INFO (("lofi_add: %s %s", name, devfs_path));
if ((d = hal_device_store_match_key_value_string (hald_get_gdl (),
"solaris.devfs_path", devfs_path)) == NULL) {
HAL_INFO (("device not found in GDL %s", devfs_path));
return;
}
parent_udi = hal_device_property_get_string (d, "info.parent");
if ((parent_udi == NULL) || (strlen(parent_udi) == 0)) {
HAL_INFO (("parent not found in GDL %s", parent_udi));
return;
}
if ((parent = hal_device_store_match_key_value_string (hald_get_gdl (),
"info.udi", parent_udi)) == NULL) {
HAL_INFO (("parent not found in GDL %s", parent_udi));
return;
}
if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
HAL_INFO (("device not found in devinfo %s", devfs_path));
return;
}
HAL_INFO (("device %s parent %s", hal_device_get_udi (d), parent_udi));
devinfo_lofi_add_major (parent, node, devfs_path, NULL, TRUE, d);
di_fini (node);
hotplug_event_process_queue ();
}
static void
drvctl_lofi_remove(gchar *parent_devfs_path, gchar *name)
{
devinfo_lofi_remove_minor(parent_devfs_path, name);
hotplug_event_process_queue ();
}
#endif