xref: /illumos-gate/usr/src/cmd/hal/hald/solaris/sysevent.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /***************************************************************************
2  *
3  * sysevent.c : Solaris sysevents
4  *
5  * Copyright 2022 Carsten Grzemba <grzemba@contac-dt.de>
6  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  *
9  * Licensed under the Academic Free License version 2.1
10  *
11  **************************************************************************/
12 
13 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16 
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <sys/dkio.h>
24 #include <sys/stat.h>
25 #include <libdevinfo.h>
26 #include <libsysevent.h>
27 #include <sys/sysevent/dev.h>
28 #include <sys/sysevent/pwrctl.h>
29 #include <sys/sysevent/dr.h>
30 #include <glib.h>
31 #include <config_admin.h>
32 #include <kstat.h>
33 
34 #include "../osspec.h"
35 #include "../logger.h"
36 #include "../hald.h"
37 #include "../hald_dbus.h"
38 #include "../device_info.h"
39 #include "../util.h"
40 #include "osspec_solaris.h"
41 #include "hotplug.h"
42 #include "devinfo.h"
43 #include "devinfo_storage.h"
44 #include "devinfo_acpi.h"
45 #include "devinfo_usb.h"
46 #include "sysevent.h"
47 #include "devinfo_misc.h"
48 #include "devinfo_cpu.h"
49 
50 #ifndef ESC_LOFI
51 #define	ESC_LOFI "lofi"
52 #endif
53 
54 static void	sysevent_dev_handler(sysevent_t *);
55 static gboolean sysevent_iochannel_data(GIOChannel *, GIOCondition, gpointer);
56 static void	sysevent_dev_add(gchar *, gchar *);
57 static void	sysevent_dev_remove(gchar *, gchar *);
58 static void	sysevent_dev_branch(gchar *);
59 static void	sysevent_lofi_add(gchar *, gchar *);
60 static void	sysevent_lofi_remove(gchar *, gchar *);
61 static void	sysevent_devfs_add(gchar *);
62 static void	sysevent_pwrctl(gchar *, gchar *, gchar *, gchar *, gchar *,
63 		    gchar *, uint_t);
64 static void	sysevent_process_dr(gchar *, gchar *);
65 
66 static sysevent_handle_t	*shp;
67 
68 static int sysevent_pipe_fds[2];
69 static GIOChannel *sysevent_iochannel;
70 static guint sysevent_source_id;
71 
72 gboolean
73 sysevent_init(void)
74 {
75 	GError *err = NULL;
76 	const char	*subcl[6];
77 
78 	/*
79 	 * pipe used to serialize sysevents through the main loop
80 	 */
81 	if (pipe (sysevent_pipe_fds) != 0) {
82 		HAL_INFO (("pipe() failed errno=%d", errno));
83 		return (FALSE);
84 	}
85 	sysevent_iochannel = g_io_channel_unix_new (sysevent_pipe_fds[0]);
86 	if (sysevent_iochannel == NULL) {
87 		HAL_INFO (("g_io_channel_unix_new failed"));
88 		return (FALSE);
89 	}
90 	g_io_channel_set_flags (sysevent_iochannel, G_IO_FLAG_NONBLOCK, &err);
91 	sysevent_source_id = g_io_add_watch (
92 	    sysevent_iochannel, G_IO_IN, sysevent_iochannel_data, NULL);
93 
94 	shp = sysevent_bind_handle(sysevent_dev_handler);
95 	if (shp == NULL) {
96 		HAL_INFO (("sysevent_bind_handle failed %d", errno));
97 		return (FALSE);
98 	}
99 
100 	subcl[0] = ESC_DISK;
101 	subcl[1] = ESC_LOFI;
102 	subcl[2] = ESC_PRINTER;
103 	if (sysevent_subscribe_event(shp, EC_DEV_ADD, subcl, 3) != 0) {
104 		HAL_INFO (("subscribe(dev_add) failed %d", errno));
105 		sysevent_unbind_handle(shp);
106 		return (FALSE);
107 	}
108 	if (sysevent_subscribe_event(shp, EC_DEV_REMOVE, subcl, 3) != 0) {
109 		HAL_INFO (("subscribe(dev_remove) failed %d", errno));
110 		sysevent_unbind_handle(shp);
111 		return (FALSE);
112 	}
113 
114 	subcl[0] = ESC_DEV_BRANCH_REMOVE;
115 	if (sysevent_subscribe_event(shp, EC_DEV_BRANCH, subcl, 1) != 0) {
116 		HAL_INFO (("subscribe(dev_branch) failed %d", errno));
117 		sysevent_unbind_handle(shp);
118 		return (FALSE);
119 	}
120 
121 	subcl[0] = ESC_PWRCTL_ADD;
122 	subcl[1] = ESC_PWRCTL_REMOVE;
123 	subcl[2] = ESC_PWRCTL_STATE_CHANGE;
124 	subcl[3] = ESC_PWRCTL_BRIGHTNESS_UP;
125 	subcl[4] = ESC_PWRCTL_BRIGHTNESS_DOWN;
126 	subcl[5] = ESC_PWRCTL_POWER_BUTTON;
127 	if (sysevent_subscribe_event(shp, EC_PWRCTL, subcl, 6) != 0) {
128 		HAL_INFO(("subscribe(dev_add) failed %d", errno));
129 		sysevent_unbind_handle(shp);
130 		return (FALSE);
131 	}
132 
133 	subcl[0] = ESC_DEVFS_DEVI_ADD;
134 	if (sysevent_subscribe_event(shp, EC_DEVFS, subcl, 1) != 0) {
135 		HAL_INFO (("subscribe(EC_DEVFS) failed %d", errno));
136 		sysevent_unbind_handle(shp);
137 		return (FALSE);
138 	}
139 
140 	subcl[0] = ESC_DR_AP_STATE_CHANGE;
141 	if (sysevent_subscribe_event(shp, EC_DR, subcl, 1) != 0) {
142 		HAL_INFO (("subscribe(dynamic reconfiguration) failed %d",
143 		    errno));
144 		sysevent_unbind_handle(shp);
145 		return (FALSE);
146 	}
147 
148 	return (B_TRUE);
149 }
150 
151 void
152 sysevent_fini(void)
153 {
154 	sysevent_unbind_handle(shp);
155 	shp = NULL;
156 }
157 
158 static void
159 sysevent_dev_handler(sysevent_t *ev)
160 {
161 	char		*class;
162 	char		*subclass;
163 	nvlist_t	*attr_list;
164 	char		*phys_path;
165 	char		*dev_name;
166 	char		*dev_hid;
167 	char		*dev_uid;
168 	uint_t		dev_index;
169 	char		s[1024];
170 	ssize_t		nwritten;
171 
172 	if ((class = sysevent_get_class_name(ev)) == NULL)
173 		return;
174 
175 	if ((subclass = sysevent_get_subclass_name(ev)) == NULL)
176 		return;
177 
178 	if (sysevent_get_attr_list(ev, &attr_list) != 0)
179 		return;
180 
181 	if (strcmp(class, EC_DEVFS) == 0) {
182 		if (nvlist_lookup_string(attr_list, DEVFS_PATHNAME, &phys_path) != 0) {
183 			goto out;
184 		}
185 
186 		snprintf(s, sizeof (s), "%s %s %s\n",
187 		    class, subclass, phys_path);
188 		nwritten = write(sysevent_pipe_fds[1], s, strlen(s));
189 
190 		HAL_INFO (("sysevent_dev_handler: wrote %d bytes", nwritten));
191 		goto out;
192 	}
193 
194 	if (strcmp(class, EC_PWRCTL) == 0) {
195 		if (nvlist_lookup_string(attr_list, PWRCTL_DEV_PHYS_PATH,
196 		    &phys_path) != 0) {
197 			goto out;
198 		}
199 	} else if (strcmp(class, EC_DR) == 0) {
200 		if (nvlist_lookup_string(attr_list, DR_AP_ID,
201 		    &phys_path) != 0) {
202 			goto out;
203 		}
204 	} else if (nvlist_lookup_string(attr_list, DEV_PHYS_PATH, &phys_path)
205 	    != 0) {
206 		goto out;
207 	}
208 
209 	/*
210 	 * In case of EC_DR, use dev_name to store DR_HINT val
211 	 */
212 	if (strcmp(class, EC_DR) == 0) {
213 		if (nvlist_lookup_string(attr_list, DR_HINT, &dev_name) != 0) {
214 			goto out;
215 		}
216 	} else if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) {
217 		if (strcmp(class, EC_PWRCTL) == 0) {
218 			dev_name = "noname";
219 		} else {
220 			dev_name = "";
221 		}
222 	}
223 
224 	if (nvlist_lookup_string(attr_list, PWRCTL_DEV_HID, &dev_hid) != 0) {
225 		dev_hid = "";
226 	}
227 	if (nvlist_lookup_string(attr_list, PWRCTL_DEV_UID, &dev_uid) != 0) {
228 		dev_uid = "";
229 	}
230 	if (nvlist_lookup_uint32(attr_list, PWRCTL_DEV_INDEX, &dev_index)
231 	    != 0) {
232 		dev_index = 0;
233 	}
234 
235 	snprintf(s, sizeof (s), "%s %s %s %s %s %s %d\n",
236 	    class, subclass, phys_path, dev_name, dev_hid, dev_uid, dev_index);
237 	nwritten = write(sysevent_pipe_fds[1], s, strlen(s));
238 
239 	HAL_INFO (("sysevent_dev_handler: wrote %d bytes", nwritten));
240 
241 out:
242 	nvlist_free(attr_list);
243 }
244 
245 static gboolean
246 sysevent_iochannel_data (GIOChannel *source,
247 		    GIOCondition condition,
248 		    gpointer user_data)
249 {
250 	GError *err = NULL;
251 	gchar *s = NULL;
252 	gsize len;
253 	int matches;
254 	gchar class[1024];
255 	gchar subclass[1024];
256 	gchar phys_path[1024];
257 	gchar dev_name[1024];
258 	gchar dev_uid[1024];
259 	gchar dev_hid[1024];
260 	uint_t dev_index;
261 
262 	HAL_INFO (("sysevent_iochannel_data"));
263 
264 	while (g_io_channel_read_line (sysevent_iochannel, &s, &len, NULL,
265 	    &err) == G_IO_STATUS_NORMAL) {
266 		if (len == 0) {
267 			break;
268 		}
269 		HAL_INFO (("IOChannel val => %s", s));
270 		class[0] = subclass[0] = phys_path[0] = dev_name[0] =
271 		    dev_hid[0] = dev_uid[0] = '\0';
272 		matches = sscanf(s, "%s %s %s %s %s %s %d", class, subclass,
273 		    phys_path, dev_name, dev_hid, dev_uid, &dev_index);
274 		g_free (s);
275 		s = NULL;
276 		if (matches < 3) {
277 			continue;
278 		}
279 		HAL_INFO (("sysevent: class=%s, sub=%s", class, subclass));
280 
281 		if (strcmp(class, EC_DEV_ADD) == 0) {
282 			if ((strcmp(subclass, ESC_DISK) == 0) ||
283 			    (strcmp(subclass, ESC_PRINTER) == 0)) {
284 				sysevent_dev_add(phys_path, dev_name);
285 			} else if (strcmp(subclass, ESC_LOFI) == 0) {
286 				sysevent_lofi_add(phys_path, dev_name);
287 			}
288 		} else if (strcmp(class, EC_DEV_REMOVE) == 0) {
289 			if ((strcmp(subclass, ESC_DISK) == 0) ||
290 			    (strcmp(subclass, ESC_PRINTER) == 0)) {
291 				sysevent_dev_remove(phys_path, dev_name);
292 			} else if (strcmp(subclass, ESC_LOFI) == 0) {
293 				sysevent_lofi_remove(phys_path, dev_name);
294 			}
295 		} else if (strcmp(class, EC_DEV_BRANCH) == 0) {
296 			sysevent_dev_branch(phys_path);
297 		} else if (strcmp(class, EC_PWRCTL) == 0) {
298 			sysevent_pwrctl(class, subclass, phys_path,
299 			    dev_name, dev_hid, dev_uid, dev_index);
300 		} else if (strcmp(class, EC_DEVFS) == 0) {
301 			if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0) {
302 				sysevent_devfs_add(phys_path);
303 			}
304 		} else if (strcmp(class, EC_DR) == 0) {
305 			/*
306 			 * Note: AP_ID is stored in phys_path and HINT is
307 			 * stored in dev_name, to avoid creating seperate
308 			 * variables and multiple conditions checking
309 			 */
310 			HAL_DEBUG (("In %s, AP_ID-> %s, Hint-> %s", class,
311 			    phys_path, dev_name));
312 			if (strcmp(subclass, ESC_DR_AP_STATE_CHANGE) == 0) {
313 				sysevent_process_dr(phys_path, dev_name);
314 			}
315 		}
316 	}
317 
318 	if (err) {
319 		g_error_free (err);
320 	}
321 
322 	return (TRUE);
323 }
324 
325 static void
326 sysevent_dev_add(gchar *devfs_path, gchar *name)
327 {
328 	gchar	*parent_devfs_path, *hotplug_devfs_path;
329 	HalDevice *parent;
330 
331 	HAL_INFO (("dev_add: %s %s", name, devfs_path));
332 
333 	parent = hal_util_find_closest_ancestor (devfs_path, &parent_devfs_path, &hotplug_devfs_path);
334 	if (parent == NULL) {
335 		return;
336 	}
337 
338 	HAL_INFO (("dev_add: parent=%s", parent_devfs_path));
339 	HAL_INFO (("dev_add: real=%s", hotplug_devfs_path));
340 
341 	devinfo_add (parent, hotplug_devfs_path);
342 
343 	g_free (parent_devfs_path);
344 	g_free (hotplug_devfs_path);
345 
346 	hotplug_event_process_queue ();
347 }
348 
349 static void
350 sysevent_dev_remove(gchar *devfs_path, gchar *name)
351 {
352 	HAL_INFO (("dev_remove: %s %s", name, devfs_path));
353 
354 	devinfo_remove_branch (devfs_path, NULL);
355 	hotplug_event_process_queue ();
356 }
357 
358 static void
359 sysevent_dev_branch(gchar *devfs_path)
360 {
361 	HAL_INFO (("branch_remove: %s", devfs_path));
362 
363 	devinfo_remove_branch (devfs_path, NULL);
364 	hotplug_event_process_queue ();
365 }
366 
367 static void
368 sysevent_lofi_add(gchar *devfs_path, gchar *name)
369 {
370 	di_node_t node;
371 	const char *parent_udi;
372 	HalDevice *d, *parent;
373 
374 	HAL_INFO (("lofi_add: %s %s", name, devfs_path));
375 
376 	if ((d = hal_device_store_match_key_value_string (hald_get_gdl (),
377 	    "solaris.devfs_path", devfs_path)) == NULL) {
378 		HAL_INFO (("device not found in GDL %s", devfs_path));
379 		return;
380 	}
381 	parent_udi = hal_device_property_get_string (d, "info.parent");
382 	if ((parent_udi == NULL) || (strlen(parent_udi) == 0)) {
383 		HAL_INFO (("parent not found in GDL %s", parent_udi));
384 		return;
385 	}
386 	if ((parent = hal_device_store_match_key_value_string (hald_get_gdl (),
387 	    "info.udi", parent_udi)) == NULL) {
388 		HAL_INFO (("parent not found in GDL %s", parent_udi));
389 		return;
390 	}
391 
392 	if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
393 		HAL_INFO (("device not found in devinfo %s", devfs_path));
394 		return;
395 	}
396 
397 	HAL_INFO (("device %s parent %s", hal_device_get_udi (d), parent_udi));
398 	devinfo_lofi_add_major (parent, node, devfs_path, NULL, TRUE, d);
399 
400 	di_fini (node);
401 
402 	hotplug_event_process_queue ();
403 }
404 
405 static void
406 sysevent_lofi_remove(gchar *parent_devfs_path, gchar *name)
407 {
408 	devinfo_lofi_remove_minor(parent_devfs_path, name);
409 	hotplug_event_process_queue ();
410 }
411 
412 static HalDevice *
413 lookup_parent(char *devfs_path)
414 {
415 	gchar		*path = NULL;
416 	HalDevice	*parent = NULL;
417 	char *p;
418 
419 	path = strdup (devfs_path);
420 	p = strrchr (path, '/');
421 	if (p == NULL) {
422 		free (path);
423 		return (NULL);
424 	}
425 	*p = '\0';
426 
427 	/* Look up the parent node in the gdl. */
428 	parent = hal_device_store_match_key_value_string (hald_get_gdl (),
429 	    "solaris.devfs_path", path);
430 
431 	if (parent == NULL) {
432 		/* Look up the parent node in the tdl. */
433 		parent = hal_device_store_match_key_value_string (hald_get_tdl (),
434 		    "solaris.devfs_path", path);
435 	}
436 
437 	free (path);
438 	return (parent);
439 }
440 
441 /*
442  * Handle the USB bus devices hot plugging events.
443  */
444 static void
445 sysevent_devfs_add(gchar *devfs_path)
446 {
447 	di_node_t node;
448 	HalDevice *parent;
449 	char *driver_name;
450 
451 	HAL_INFO (("devfs_handle: %s", devfs_path));
452 
453 	if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
454 		HAL_INFO (("device not found in devinfo %s", devfs_path));
455 		return;
456 	}
457 
458 	if ((driver_name = di_driver_name (node)) == NULL)
459 		goto out;
460 
461 	/* The disk and printer devices are handled by EC_DEV_ADD class. */
462 	if ((strcmp (driver_name, "scsa2usb") == 0) ||
463 	    (strcmp (driver_name, "usbprn") == 0))
464 		goto out;
465 
466 	if ((parent = lookup_parent (devfs_path)) == NULL)
467 		goto out;
468 
469 	devinfo_usb_add (parent, node, devfs_path, NULL);
470 
471 	di_fini (node);
472 
473 	hotplug_event_process_queue ();
474 
475 	return;
476 
477  out:
478 	di_fini (node);
479 }
480 
481 static void
482 sysevent_pwrctl(gchar *class, gchar *subclass, gchar *phys_path,
483     gchar *dev_name, gchar *dev_hid, gchar *dev_uid, uint_t dev_index)
484 {
485 	const gchar prefix[] = "/org/freedesktop/Hal/devices/pseudo/acpi_drv_0";
486 	gchar udi[HAL_PATH_MAX];
487 
488 	if (strcmp(dev_hid, "PNP0C0A") == 0) {
489 		snprintf(udi, sizeof(udi), "%s_battery%d_0", prefix, dev_index);
490 		devinfo_battery_rescan(phys_path, udi);
491 	} else if (strcmp(dev_hid, "ACPI0003") == 0) {
492 		snprintf(udi, sizeof (udi), "%s_ac%d_0", prefix, dev_index);
493 		devinfo_battery_rescan(phys_path, udi);
494 	} else if (strcmp(dev_hid, "PNP0C0D") == 0) {
495 		snprintf(udi, sizeof (udi), "%s_lid_0", prefix);
496 		devinfo_lid_event(subclass, udi);
497 	} else if (strcmp(subclass, ESC_PWRCTL_POWER_BUTTON) == 0) {
498 		devinfo_power_button_event();
499 	} else if ((strcmp(subclass, ESC_PWRCTL_BRIGHTNESS_UP) == 0) ||
500 	    (strcmp(subclass, ESC_PWRCTL_BRIGHTNESS_DOWN) == 0)) {
501 		devinfo_brightness_hotkeys_event(subclass);
502 	} else {
503 		HAL_INFO(("Unmatched EC_PWRCTL"));
504 	}
505 }
506 
507 static void
508 sysevent_dr_remove_cpu()
509 {
510 
511 	HalDeviceStore	*gdl;
512 	GSList		*iter;
513 	HalDevice	*d, *del_dev;
514 	int		cpu_id, del_cpuid;
515 	kstat_ctl_t	*kc;
516 	kstat_t		*ksp;
517 	kstat_named_t	*ksdata;
518 	const char	*cpu_devfs_path;
519 	/*
520 	 * Find the CPU's that are DR removed. For each "processor" device in
521 	 * HAL device tree, check if it has its corresponding kstat_info. If
522 	 * not, then, that cpu has been removed and can remove the entry from
523 	 * HAL entry
524 	 */
525 
526 	HAL_DEBUG (("sysevent_dr_remove_cpu()"));
527 	kc = kstat_open ();
528 	if (kc == NULL) {
529 		HAL_INFO (("Error in removing HAL cpu entry during DR. Could"
530 		    " not open kstat to get cpu info: %s", strerror (errno)));
531 		return;
532 	}
533 
534 	/*
535 	 * Iterate through the HAL device list to get the processor devices
536 	 */
537 	gdl = hald_get_gdl ();
538 	iter = gdl->devices;
539 
540 	while (iter != NULL) {
541 		d = HAL_DEVICE (iter->data);
542 
543 		if (!hal_device_has_property (d, "processor.number")) {
544 			iter = iter->next;
545 			continue;
546 		}
547 
548 		cpu_id = hal_device_property_get_int (d, "processor.number");
549 
550 		/*
551 		 * Check if the above cpu_id has its info in kstat
552 		 */
553 
554 		ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL);
555 		if (ksp != NULL) {
556 			iter = iter->next;
557 			continue;
558 		}
559 		/*
560 		 *  kstat info not found. Delete the device entry
561 		 */
562 		HAL_INFO ((" Remove CPU entry: %d", cpu_id));
563 		iter = iter->next;
564 		cpu_devfs_path = hal_device_property_get_string (d,
565 		    "solaris.devfs_path");
566 		if (cpu_devfs_path == NULL) {
567 			HAL_INFO (("Could not get cpu_devfs_path to "
568 			    "remove for cpu_id %d", cpu_id));
569 		} else {
570 			/*
571 			 * Remove the cpu device
572 			 */
573 			HAL_DEBUG (("Queue %s for removal", cpu_devfs_path));
574 			devinfo_remove_enqueue ((char *)cpu_devfs_path, NULL);
575 			hotplug_event_process_queue ();
576 		}
577 	}
578 
579 	if (kc) {
580 		kstat_close (kc);
581 	}
582 }
583 
584 int
585 sysevent_dr_insert_cpu(di_node_t node, void *arg)
586 {
587 	char	*devfs_path;
588 	char	*device_type = NULL;
589 	DevinfoDevHandler *dh;
590 
591 	dh = &devinfo_cpu_handler;
592 	devfs_path = di_devfs_path (node);
593 
594 	(void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
595 	    &device_type);
596 
597 	dh->add (NULL, node, devfs_path, device_type);
598 
599 	di_devfs_path_free (devfs_path);
600 	return (DI_WALK_CONTINUE);
601 }
602 
603 /*
604  * Remove/Add the DR event device
605  * Note: Currently it supports only CPU DR events
606  */
607 static void
608 sysevent_process_dr(gchar *ap_id, gchar *hint_val)
609 {
610 	cfga_err_t		cfgerr;
611 	cfga_list_data_t	*cfg_stat;
612 	int			nlist;
613 	char			*errstr;
614 	di_node_t		root_node;
615 
616 	if ((ap_id == NULL) || (hint_val == NULL))
617 		return;
618 	HAL_DEBUG (("sysevent_process_dr: %s", ap_id));
619 
620 	cfgerr = config_list_ext (1, (char *const *)&ap_id, &cfg_stat, &nlist,
621 	    NULL, NULL, &errstr, 0);
622 
623 	if (cfgerr != CFGA_OK) {
624 		HAL_INFO (("DR sysevent process %d config_list_ext error: %s",
625 		    ap_id, errstr));
626 		goto out;
627 	}
628 	/*
629 	 * Check if the device type is CPU
630 	 */
631 	HAL_DEBUG ((" Ap-Type: %s, State: %d", cfg_stat->ap_type,
632 	    cfg_stat->ap_r_state));
633 	if (strcmp (cfg_stat->ap_type, "CPU") == 0) {
634 		if (strcmp (hint_val, DR_HINT_REMOVE) == 0) {
635 			sysevent_dr_remove_cpu();
636 		} else if (strcmp (hint_val, DR_HINT_INSERT) == 0) {
637 			/*
638 			 * Go through the device list and add the new cpu
639 			 * entries into HAL
640 			 */
641 			if ((root_node =
642 			    di_init ("/", DINFOCPYALL)) == DI_NODE_NIL) {
643 				HAL_INFO (("di_init failed. "\
644 				    "Cannot insert CPU"));
645 				goto out;
646 			}
647 			di_walk_node (root_node, DI_WALK_CLDFIRST, NULL,
648 			    sysevent_dr_insert_cpu);
649 			di_fini (root_node);
650 			hotplug_event_process_queue ();
651 		}
652 	} else {
653 		HAL_INFO (("Not a CPU, so cannot DR"));
654 	}
655 
656 out:
657 	if (cfg_stat)
658 		free (cfg_stat);
659 	if (errstr)
660 		free (errstr);
661 }
662