4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/param.h>
38 #include <sys/nvpair.h>
39 #include "libdevice.h"
41 static int _libdevice_debug
= 0;
42 static const char *devctl_minorname
= ":devctl";
43 static const char *nullptr = "<null>";
44 static const char *devctl_target_raw
= "a,raw";
46 typedef enum { DEVCTL_BUS
, DEVCTL_DEVICE
, DEVCTL_AP
, DEVCTL_CLONE
,
47 DEVCTL_PM_DEV
, DEVCTL_PM_BUS
} dc_type_t
;
50 * devctl_hdl structures are allocated by the devctl_XX_acquire()
51 * interfaces and passed to the remaining interfaces in this library.
54 char *opath
; /* copy of the original path */
55 dc_type_t hdltype
; /* handle type */
56 int fd
; /* nexus device node */
57 char *nodename
; /* DEVCTL_DEVICE handles only */
58 char *unitaddr
; /* DEVCTL_DEVICE handles only */
60 #define DCP(x) ((struct devctl_hdl *)(x))
62 static int dc_cmd(uint_t
, uint_t
, struct devctl_hdl
*, nvlist_t
*, void *);
63 static devctl_hdl_t
dc_mkhndl(dc_type_t
, char *, uint_t
, devctl_hdl_t
);
66 #pragma init(_libdevice_init)
70 _libdevice_debug
= getenv("LIBDEVICE_DEBUG") != NULL
;
74 * release a devctl_hdl structure
77 devctl_release(devctl_hdl_t hdl
)
80 (void) printf("devctl_release: %p\n", (void *)hdl
);
85 if (DCP(hdl
)->fd
!= -1)
86 (void) close(DCP(hdl
)->fd
);
88 free(DCP(hdl
)->opath
);
90 free(DCP(hdl
)->nodename
);
92 free(DCP(hdl
)->unitaddr
);
98 * construct a handle suitable for devctl_bus_*() operations
101 devctl_bus_acquire(char *devfs_path
, uint_t flags
)
105 if (_libdevice_debug
)
106 (void) printf("devctl_bus_acquire: %s (%d)\n",
107 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
109 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
114 oflags
= ((flags
& DC_EXCL
) != 0) ? O_EXCL
|O_RDWR
: O_RDWR
;
115 return (dc_mkhndl(DEVCTL_BUS
, devfs_path
, oflags
, NULL
));
120 * construct a handle suitable for devctl_bus_*() and
121 * devctl_device_*() operations.
124 devctl_device_acquire(char *devfs_path
, uint_t flags
)
128 if (_libdevice_debug
)
129 (void) printf("devctl_device_acquire: %s (%d)\n",
130 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
132 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
137 oflags
= ((flags
& DC_EXCL
) != 0) ? O_EXCL
|O_RDWR
: O_RDWR
;
138 return (dc_mkhndl(DEVCTL_DEVICE
, devfs_path
, oflags
, NULL
));
143 * given a devfs (/devices) pathname to an attachment point device,
144 * access the device and return a handle to be passed to the
145 * devctl_ap_XXX() functions.
148 devctl_ap_acquire(char *devfs_path
, uint_t flags
)
152 if (_libdevice_debug
)
153 (void) printf("devctl_ap_acquire: %s (%d)\n",
154 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
156 if ((devfs_path
== NULL
) ||
157 ((flags
!= 0) && ((flags
& DC_EXCL
) != 0) &&
158 ((flags
& DC_RDONLY
) != 0))) {
163 oflags
= ((flags
& DC_EXCL
) != 0) ? O_EXCL
: 0;
164 oflags
|= ((flags
& DC_RDONLY
) != 0) ? O_RDONLY
: O_RDWR
;
166 return (dc_mkhndl(DEVCTL_AP
, devfs_path
, oflags
, NULL
));
171 * given a devfs (/devices) pathname access the device and return
172 * a handle to be passed to the devctl_pm_XXX() functions.
173 * The minor name ":devctl" is appended.
176 devctl_pm_bus_acquire(char *devfs_path
, uint_t flags
)
180 if (_libdevice_debug
)
181 (void) printf("devctl_pm_bus_acquire: %s (%d)\n",
182 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
184 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
189 oflags
= ((flags
& DC_EXCL
) != 0) ? (O_EXCL
| O_RDWR
) : O_RDWR
;
190 return (dc_mkhndl(DEVCTL_PM_BUS
, devfs_path
, oflags
, NULL
));
195 * given a devfs (/devices) pathname access the device and return
196 * a handle to be passed to the devctl_pm_XXX() functions.
197 * The minor name is derived from the device name.
200 devctl_pm_dev_acquire(char *devfs_path
, uint_t flags
)
204 if (_libdevice_debug
)
205 (void) printf("devctl_pm_dev_acquire: %s (%d)\n",
206 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
208 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
213 oflags
= ((flags
& DC_EXCL
) != 0) ? (O_EXCL
| O_RDWR
) : O_RDWR
;
214 return (dc_mkhndl(DEVCTL_PM_DEV
, devfs_path
, oflags
, NULL
));
219 * allocate and initalize the devctl_hdl structure for the
220 * particular handle type.
223 dc_mkhndl(dc_type_t type
, char *path
, uint_t oflags
, devctl_hdl_t pc
)
225 struct devctl_hdl
*dcp
;
227 char iocpath
[MAXPATHLEN
];
228 char *nodename
, *unitsep
, *minorsep
, *chop
;
234 if ((path
== NULL
) || (strlen(path
) > MAXPATHLEN
- 1)) {
240 * allocate handle and make a copy of the original path
242 if ((dcp
= calloc(1, sizeof (*dcp
))) == NULL
) {
246 if ((dcp
->opath
= strdup(path
)) == NULL
) {
247 devctl_release((devctl_hdl_t
)dcp
);
252 (void) strcpy(iocpath
, path
);
257 * break apart the pathname according to the type handle
262 * chop off any minor name and concatenate the
263 * ":devctl" minor node name string.
265 if ((chop
= strrchr(iocpath
, ':')) != NULL
)
268 if (strlcat(iocpath
, devctl_minorname
, MAXPATHLEN
) >=
270 devctl_release((devctl_hdl_t
)dcp
);
273 } else if (_libdevice_debug
) {
274 (void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath
);
280 * Chop up the last device component in the pathname.
281 * Concatenate either the device name itself, or the
282 * "a,raw" string, as the minor node name, to the iocpath.
284 if ((iocpath_dup
= strdup(iocpath
)) == NULL
) {
285 devctl_release((devctl_hdl_t
)dcp
);
289 if ((chop
= strrchr(iocpath_dup
, '/')) == NULL
) {
290 devctl_release((devctl_hdl_t
)dcp
);
298 * remove the "@0,0" string
300 tok
= strtok(nodename
, "@");
301 if ((minorname
= malloc(strlen(tok
) +1)) == NULL
) {
302 if (_libdevice_debug
)
303 (void) printf("DEVCTL_PM_DEV: failed malloc for"
305 devctl_release((devctl_hdl_t
)dcp
);
309 (void) strcpy(minorname
, tok
);
310 if (_libdevice_debug
) {
311 (void) printf("DEVCTL_PM_DEV: minorname %s\n",
316 * construct the name of the ioctl device
317 * by concatenating either ":a,raw" or ":"minorname
319 (void) strlcat(iocpath
, ":", MAXPATHLEN
);
320 if (strcmp(minorname
, "disk_chan") == 0 ||
321 strcmp(minorname
, "disk_wwn") == 0 ||
322 strcmp(minorname
, "disk_cdrom") == 0) {
323 strlcpy_size
= strlcat(iocpath
, devctl_target_raw
,
326 strlcpy_size
= strlcat(iocpath
, minorname
, MAXPATHLEN
);
328 if (strlcpy_size
>= MAXPATHLEN
) {
329 devctl_release((devctl_hdl_t
)dcp
);
332 } else if (_libdevice_debug
) {
333 (void) printf("DEVCTL_PM_DEV: iocpath %s\n",
340 * take the pathname as provided.
346 * chop off any minor name and concatenate the
347 * ":devctl" minor node name string.
349 if ((chop
= strrchr(iocpath
, ':')) != NULL
)
352 if (strlcat(iocpath
, devctl_minorname
, MAXPATHLEN
) >=
354 devctl_release((devctl_hdl_t
)dcp
);
362 * create a device handle for a new device created
363 * from a call to devctl_bus_dev_create()
365 dcp
->hdltype
= DEVCTL_DEVICE
;
372 * Chop up the last device component in the pathname.
373 * The componets are passed as nodename and unitaddr
374 * in the IOCTL data for DEVCTL ops on devices.
376 if ((chop
= strrchr(iocpath
, '/')) == NULL
) {
377 devctl_release((devctl_hdl_t
)dcp
);
384 unitsep
= strchr(nodename
, '@');
385 minorsep
= strchr(nodename
, ':');
387 if (unitsep
== NULL
) {
388 devctl_release((devctl_hdl_t
)dcp
);
394 * copy the nodename and unit address
396 if (((dcp
->nodename
= malloc(MAXNAMELEN
)) == NULL
) ||
397 ((dcp
->unitaddr
= malloc(MAXNAMELEN
)) == NULL
)) {
398 devctl_release((devctl_hdl_t
)dcp
);
403 if (minorsep
!= NULL
)
405 (void) snprintf(dcp
->nodename
, MAXNAMELEN
, "%s", nodename
);
406 (void) snprintf(dcp
->unitaddr
, MAXNAMELEN
, "%s", unitsep
+1);
409 * construct the name of the ioctl device
411 if (strlcat(iocpath
, devctl_minorname
, MAXPATHLEN
) >=
413 devctl_release((devctl_hdl_t
)dcp
);
420 devctl_release((devctl_hdl_t
)dcp
);
425 if (_libdevice_debug
)
426 (void) printf("dc_mkhndl: iocpath %s ", iocpath
);
429 * verify the devctl or ap device exists and is a
430 * character device interface.
432 if (stat(iocpath
, &sb
) == 0) {
433 if ((sb
.st_mode
& S_IFMT
) != S_IFCHR
) {
434 if (_libdevice_debug
)
435 (void) printf(" - not character device\n");
437 devctl_release((devctl_hdl_t
)dcp
);
442 * return failure with errno value set by stat
444 if (_libdevice_debug
)
445 (void) printf(" - stat failed\n");
446 devctl_release((devctl_hdl_t
)dcp
);
451 * if this was a new device, dup the parents handle, otherwise
452 * just open the device.
454 if (type
== DEVCTL_CLONE
)
455 dcp
->fd
= dup(DCP(pc
)->fd
);
457 dcp
->fd
= open(iocpath
, oflags
);
460 if (_libdevice_debug
)
461 (void) printf(" - open/dup failed %d\n", errno
);
463 * leave errno as set by open/dup
465 devctl_release((devctl_hdl_t
)dcp
);
469 if (_libdevice_debug
)
470 (void) printf(" - open success\n");
472 return ((devctl_hdl_t
)dcp
);
476 * Power up component 0, to level MAXPWR, via a pm_raise_power() call
479 devctl_pm_raisepower(devctl_hdl_t dcp
)
483 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
484 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
489 rv
= dc_cmd(DEVCTL_PM_RAISE_PWR
, 0, DCP(dcp
), NULL
, NULL
);
491 if (_libdevice_debug
)
492 (void) printf("devctl_pm_raisepower: %d\n", rv
);
498 * Power up component 0, to level MAXPWR, via a power_has_changed() call
501 devctl_pm_changepowerhigh(devctl_hdl_t dcp
)
505 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
506 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
511 rv
= dc_cmd(DEVCTL_PM_CHANGE_PWR_HIGH
, 0, DCP(dcp
), NULL
, NULL
);
513 if (_libdevice_debug
)
514 (void) printf("devctl_pm_changepowerhigh: %d\n", rv
);
520 * Power down component 0, to level 0, via a pm_change_power() call
523 devctl_pm_changepowerlow(devctl_hdl_t dcp
)
527 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
528 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
533 rv
= dc_cmd(DEVCTL_PM_CHANGE_PWR_LOW
, 0, DCP(dcp
), NULL
, NULL
);
535 if (_libdevice_debug
)
536 (void) printf("devctl_pm_changepowerlow: %d\n", rv
);
542 * mark component 0 idle
545 devctl_pm_idlecomponent(devctl_hdl_t dcp
)
549 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
550 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
555 rv
= dc_cmd(DEVCTL_PM_IDLE_COMP
, 0, DCP(dcp
), NULL
, NULL
);
557 if (_libdevice_debug
)
558 (void) printf("devctl_pm_idlecomponent: %d\n", rv
);
564 * mark component 0 busy
567 devctl_pm_busycomponent(devctl_hdl_t dcp
)
571 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
572 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
577 rv
= dc_cmd(DEVCTL_PM_BUSY_COMP
, 0, DCP(dcp
), NULL
, NULL
);
579 if (_libdevice_debug
)
580 (void) printf("devctl_pm_busycomponent: %d\n", rv
);
589 devctl_pm_testbusy(devctl_hdl_t dcp
, uint_t
*busystate
)
592 uint_t busy_state
= 0;
594 if (busystate
== NULL
) {
599 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
600 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
605 rv
= dc_cmd(DEVCTL_PM_BUSY_COMP_TEST
, 0, DCP(dcp
), NULL
,
606 (void *)&busy_state
);
611 *busystate
= busy_state
;
613 if (_libdevice_debug
)
614 (void) printf("devctl_pm_bus_testbusy: rv %d busystate %x\n",
621 * set flag to fail DDI_SUSPEND
624 devctl_pm_failsuspend(devctl_hdl_t dcp
)
628 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
629 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
634 rv
= dc_cmd(DEVCTL_PM_FAIL_SUSPEND
, 0, DCP(dcp
), NULL
, NULL
);
636 if (_libdevice_debug
)
637 (void) printf("devctl_pm_failsuspend: %d\n", rv
);
642 devctl_pm_bus_teststrict(devctl_hdl_t dcp
, uint_t
*strict
)
647 if (strict
== NULL
) {
652 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
657 rv
= dc_cmd(DEVCTL_PM_BUS_STRICT_TEST
, 0, DCP(dcp
), NULL
,
658 (void *)&strict_state
);
663 *strict
= strict_state
;
665 if (_libdevice_debug
)
666 (void) printf("devctl_pm_bus_teststrict: rv %d strict %x\n",
673 * issue prom_printf() call
676 devctl_pm_device_promprintf(devctl_hdl_t dcp
)
680 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
681 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
686 rv
= dc_cmd(DEVCTL_PM_PROM_PRINTF
, 0, DCP(dcp
), NULL
, NULL
);
688 if (_libdevice_debug
)
689 (void) printf("devctl_pm_device_promprintf: %d\n", rv
);
694 * set flag to power up the device via
695 * pm_power_has_changed() calls vs.
696 * pm_raise_power(), during DDI_RESUME
699 devctl_pm_device_changeonresume(devctl_hdl_t dcp
)
703 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
704 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
709 rv
= dc_cmd(DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME
, 0,
710 DCP(dcp
), NULL
, NULL
);
712 if (_libdevice_debug
)
713 (void) printf("devctl_pm_device_changeonresume: %d\n", rv
);
718 * issue DEVCTL_PM_NO_LOWER_POWER to clear the LOWER_POWER_FLAG
719 * flag: pm_lower_power() will not be called on device detach
722 devctl_pm_device_no_lower_power(devctl_hdl_t dcp
)
726 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
) {
731 rv
= dc_cmd(DEVCTL_PM_NO_LOWER_POWER
, 0, DCP(dcp
), NULL
, NULL
);
733 if (_libdevice_debug
)
734 (void) printf("devctl_pm_device_no_lower_power: %d\n", rv
);
739 * issue DEVCTL_PM_BUS_NO_INVOL ioctl to set the NO_INVOL_FLAG
740 * flag: parent driver will mark itself idle twice in
741 * DDI_CTLOPS_DETACH(POST)
744 devctl_pm_bus_no_invol(devctl_hdl_t dcp
)
748 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
) {
753 rv
= dc_cmd(DEVCTL_PM_BUS_NO_INVOL
, 0, DCP(dcp
), NULL
, NULL
);
755 if (_libdevice_debug
)
756 (void) printf("devctl_pm_bus_no_invol: %d\n", rv
);
761 * Place the device ONLINE
764 devctl_device_online(devctl_hdl_t dcp
)
768 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_DEVICE
) {
773 rv
= dc_cmd(DEVCTL_DEVICE_ONLINE
, 0, DCP(dcp
), NULL
, NULL
);
775 if (_libdevice_debug
)
776 (void) printf("devctl_device_online: %d\n", rv
);
782 * take device OFFLINE
785 devctl_device_offline(devctl_hdl_t dcp
)
789 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_DEVICE
) {
794 rv
= dc_cmd(DEVCTL_DEVICE_OFFLINE
, 0, DCP(dcp
), NULL
, NULL
);
796 if (_libdevice_debug
)
797 (void) printf("devctl_device_offline: %d\n", rv
);
803 * take the device OFFLINE and remove its dev_info node
806 devctl_device_remove(devctl_hdl_t dcp
)
810 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_DEVICE
) {
815 rv
= dc_cmd(DEVCTL_DEVICE_REMOVE
, 0, DCP(dcp
), NULL
, NULL
);
817 if (_libdevice_debug
)
818 (void) printf("devctl_device_remove: %d\n", rv
);
828 devctl_bus_quiesce(devctl_hdl_t dcp
)
832 rv
= dc_cmd(DEVCTL_BUS_QUIESCE
, 0, DCP(dcp
), NULL
, NULL
);
834 if (_libdevice_debug
)
835 (void) printf("devctl_bus_quiesce: %d\n", rv
);
841 devctl_bus_unquiesce(devctl_hdl_t dcp
)
845 rv
= dc_cmd(DEVCTL_BUS_UNQUIESCE
, 0, DCP(dcp
), NULL
, NULL
);
847 if (_libdevice_debug
)
848 (void) printf("devctl_bus_unquiesce: %d\n", rv
);
854 devctl_bus_reset(devctl_hdl_t dcp
)
858 rv
= dc_cmd(DEVCTL_BUS_RESET
, 0, DCP(dcp
), NULL
, NULL
);
860 if (_libdevice_debug
)
861 (void) printf("devctl_bus_reset: %d\n", rv
);
867 devctl_bus_resetall(devctl_hdl_t dcp
)
871 rv
= dc_cmd(DEVCTL_BUS_RESETALL
, 0, DCP(dcp
), NULL
, NULL
);
873 if (_libdevice_debug
)
874 (void) printf("devctl_bus_resetall: %d\n", rv
);
880 devctl_device_reset(devctl_hdl_t dcp
)
884 rv
= dc_cmd(DEVCTL_DEVICE_RESET
, 0, DCP(dcp
), NULL
, NULL
);
886 if (_libdevice_debug
)
887 (void) printf("devctl_device_reset: %d\n", rv
);
893 devctl_device_getstate(devctl_hdl_t dcp
, uint_t
*devstate
)
898 if (devstate
== NULL
) {
903 rv
= dc_cmd(DEVCTL_DEVICE_GETSTATE
, 0, DCP(dcp
), NULL
,
904 (void *)&device_state
);
909 *devstate
= device_state
;
911 if (_libdevice_debug
)
912 (void) printf("devctl_device_getstate: rv %d state %x\n",
919 devctl_bus_getstate(devctl_hdl_t dcp
, uint_t
*devstate
)
924 if (devstate
== NULL
) {
929 rv
= dc_cmd(DEVCTL_BUS_GETSTATE
, 0, DCP(dcp
), NULL
,
930 (void *)&device_state
);
935 *devstate
= device_state
;
937 if (_libdevice_debug
)
938 (void) printf("devctl_bus_getstate: rv %d, state %x\n",
945 devctl_bus_configure(devctl_hdl_t dcp
)
949 rv
= dc_cmd(DEVCTL_BUS_CONFIGURE
, 0, DCP(dcp
), NULL
, NULL
);
951 if (_libdevice_debug
)
952 (void) printf("devctl_bus_configure: %d\n", rv
);
958 devctl_bus_unconfigure(devctl_hdl_t dcp
)
962 rv
= dc_cmd(DEVCTL_BUS_UNCONFIGURE
, 0, DCP(dcp
), NULL
, NULL
);
964 if (_libdevice_debug
)
965 (void) printf("devctl_bus_unconfigure: %d\n", rv
);
971 * devctl_bus_dev_create() - create a new child device
972 * Attempt to construct and attach a new child device below a
973 * bus nexus (dcp). The device is defined using the devctl_ddef_*()
974 * routines to specify the set of bus-specific properties required
975 * to initalize and attach the device.
978 devctl_bus_dev_create(devctl_hdl_t dcp
, devctl_ddef_t ddef_hdl
,
979 uint_t flags
, devctl_hdl_t
*new_dcp
)
981 char devname
[MAXNAMELEN
];
982 char devpath
[MAXPATHLEN
];
985 if (dcp
== NULL
|| ddef_hdl
== NULL
) {
990 (void) memset(devname
, 0, sizeof (devname
));
991 rv
= dc_cmd(DEVCTL_BUS_DEV_CREATE
, flags
, DCP(dcp
),
992 (nvlist_t
*)ddef_hdl
, devname
);
995 * construct a device handle for the new device
997 if ((rv
== 0) && (new_dcp
!= NULL
)) {
998 char *minorname
, *lastslash
;
1000 (void) memset(devpath
, 0, sizeof (devpath
));
1001 (void) strcat(devpath
, DCP(dcp
)->opath
);
1004 * Take the pathname of the parent device, chop off
1005 * any minor name info, and append the name@addr of
1006 * the new child device.
1007 * Call dc_mkhndl() with this constructed path and
1008 * the CLONE handle type to create a new handle which
1009 * references the new child device.
1011 lastslash
= strrchr(devpath
, '/');
1012 if (*(lastslash
+ 1) == '\0') {
1015 if ((minorname
= strchr(lastslash
, ':')) != NULL
)
1018 (void) strcat(devpath
, "/");
1019 (void) strlcat(devpath
, devname
, MAXPATHLEN
);
1020 *new_dcp
= dc_mkhndl(DEVCTL_CLONE
, devpath
, 0, dcp
);
1021 if (*new_dcp
== NULL
)
1029 devctl_ap_connect(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1033 rv
= dc_cmd(DEVCTL_AP_CONNECT
, 0, DCP(dcp
), ap_data
, NULL
);
1035 if (_libdevice_debug
)
1036 (void) printf("devctl_ap_connect: %d\n", rv
);
1042 devctl_ap_disconnect(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1046 rv
= dc_cmd(DEVCTL_AP_DISCONNECT
, 0, DCP(dcp
), ap_data
, NULL
);
1048 if (_libdevice_debug
)
1049 (void) printf("devctl_ap_disconnect: %d\n", rv
);
1055 devctl_ap_insert(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1059 rv
= dc_cmd(DEVCTL_AP_INSERT
, 0, DCP(dcp
), ap_data
, NULL
);
1061 if (_libdevice_debug
)
1062 (void) printf("devctl_ap_insert: %d\n", rv
);
1068 devctl_ap_remove(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1072 rv
= dc_cmd(DEVCTL_AP_REMOVE
, 0, DCP(dcp
), ap_data
, NULL
);
1074 if (_libdevice_debug
)
1075 (void) printf("devctl_ap_remove: %d\n", rv
);
1081 devctl_ap_configure(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1085 rv
= dc_cmd(DEVCTL_AP_CONFIGURE
, 0, DCP(dcp
), ap_data
, NULL
);
1087 if (_libdevice_debug
)
1088 (void) printf("devctl_ap_configure: %d\n", rv
);
1094 devctl_ap_unconfigure(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1098 rv
= dc_cmd(DEVCTL_AP_UNCONFIGURE
, 0, DCP(dcp
), ap_data
, NULL
);
1100 if (_libdevice_debug
)
1101 (void) printf("devctl_ap_unconfigure: %d\n", rv
);
1107 devctl_ap_getstate(devctl_hdl_t dcp
, nvlist_t
*ap_data
,
1108 devctl_ap_state_t
*apstate
)
1111 devctl_ap_state_t ap_state
;
1113 rv
= dc_cmd(DEVCTL_AP_GETSTATE
, 0, DCP(dcp
), ap_data
,
1117 (void) memset(apstate
, 0, sizeof (struct devctl_ap_state
));
1119 *apstate
= ap_state
;
1121 if (_libdevice_debug
)
1122 (void) printf("devctl_ap_getstate: %d\n", rv
);
1128 * Allocate a device 'definition' handle, in reality a list of
1133 devctl_ddef_alloc(char *nodename
, int flags
)
1138 if ((nodename
== NULL
) || *nodename
== '\0') {
1144 * allocate nvlist structure which is returned as an
1145 * opaque handle to the caller. If this fails, return
1146 * NULL with errno left set to the value
1148 if (nvlist_alloc(&nvlp
, NV_UNIQUE_NAME_TYPE
, 0) != 0) {
1154 * add the nodename of the new device to the list
1156 if (nvlist_add_string(nvlp
, DC_DEVI_NODENAME
, nodename
) != 0) {
1162 if (_libdevice_debug
)
1163 (void) printf("devctl_ddef_alloc: node %s nvp %p\n", nodename
,
1166 return ((devctl_ddef_t
)nvlp
);
1170 * free the definition handle
1173 devctl_ddef_free(devctl_ddef_t ddef_hdl
)
1175 if (_libdevice_debug
)
1176 (void) printf("devctl_ddef_free: nvp %p\n", (void *)ddef_hdl
);
1178 nvlist_free((nvlist_t
*)ddef_hdl
);
1182 * define an integer property
1185 devctl_ddef_int(devctl_ddef_t ddef_hdl
, char *name
, int32_t value
)
1190 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1195 rv
= nvlist_add_int32((nvlist_t
*)ddef_hdl
, name
, value
);
1197 if (_libdevice_debug
)
1198 (void) printf("devctl_ddef_int: rv %d nvp %p name %s val %d\n",
1199 rv
, (void *)ddef_hdl
, name
, value
);
1205 * define an integer array property
1208 devctl_ddef_int_array(devctl_ddef_t ddef_hdl
, char *name
, int nelements
,
1213 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1218 rv
= nvlist_add_int32_array((nvlist_t
*)ddef_hdl
, name
, value
,
1221 if (_libdevice_debug
) {
1222 (void) printf("devctl_ddef_int_array: rv %d nvp %p name %s: ",
1223 rv
, (void *)ddef_hdl
, name
);
1224 for (i
= 0; i
< nelements
; i
++)
1225 (void) printf("0x%x ", value
[i
]);
1226 (void) printf("\n");
1233 * define a string property
1236 devctl_ddef_string(devctl_ddef_t ddef_hdl
, char *name
, char *value
)
1240 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1245 rv
= nvlist_add_string((nvlist_t
*)ddef_hdl
, name
, value
);
1247 if (_libdevice_debug
)
1248 (void) printf("devctl_ddef_string: rv %d nvp %p %s=\"%s\"\n",
1249 rv
, (void *)ddef_hdl
, name
, value
);
1255 * define a string array property
1258 devctl_ddef_string_array(devctl_ddef_t ddef_hdl
, char *name
, int nelements
,
1263 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1268 rv
= nvlist_add_string_array((nvlist_t
*)ddef_hdl
, name
,
1271 if (_libdevice_debug
) {
1272 (void) printf("devctl_ddef_string_array: rv %d nvp %p "
1273 "name %s:\n", rv
, (void *)ddef_hdl
, name
);
1274 for (i
= 0; i
< nelements
; i
++)
1275 (void) printf("\t%d: \"%s\"\n", i
, value
[i
]);
1281 * define a byte array property
1284 devctl_ddef_byte_array(devctl_ddef_t ddef_hdl
, char *name
, int nelements
,
1289 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1294 rv
= nvlist_add_byte_array((nvlist_t
*)ddef_hdl
, name
, value
,
1301 * return the pathname which was used to acquire the handle
1304 devctl_get_pathname(devctl_hdl_t dcp
, char *pathbuf
, size_t bufsz
)
1306 if (dcp
== NULL
|| pathbuf
== NULL
|| bufsz
== 0) {
1311 (void) snprintf(pathbuf
, bufsz
, "%s", DCP(dcp
)->opath
);
1317 * execute the IOCTL request
1320 dc_cmd(uint_t cmd
, uint_t flags
, struct devctl_hdl
*dcp
, nvlist_t
*ulp
,
1323 struct devctl_iocdata iocdata
;
1326 if (_libdevice_debug
)
1327 (void) printf("dc_cmd: %x dcp %p ulp %p flags %x rv %p\n", cmd
,
1328 (void *)dcp
, (void *)ulp
, flags
, retinfo
);
1330 if ((dcp
== NULL
) || (DCP(dcp
)->fd
== -1)) {
1335 (void) memset(&iocdata
, 0, sizeof (struct devctl_iocdata
));
1338 * if there was any user supplied data in the form of a nvlist,
1339 * pack the list prior to copyin.
1342 if (rv
= nvlist_pack(ulp
, (char **)&iocdata
.nvl_user
,
1343 &iocdata
.nvl_usersz
, NV_ENCODE_NATIVE
, 0)) {
1345 * exit with errno set by nvlist_pack()
1350 iocdata
.nvl_user
= NULL
;
1351 iocdata
.nvl_usersz
= 0;
1355 * finish initalizing the request and execute the IOCTL
1358 iocdata
.flags
= flags
;
1359 iocdata
.c_nodename
= dcp
->nodename
;
1360 iocdata
.c_unitaddr
= dcp
->unitaddr
;
1361 iocdata
.cpyout_buf
= retinfo
;
1362 rv
= ioctl(dcp
->fd
, cmd
, &iocdata
);
1363 if (rv
< 0 && _libdevice_debug
) {
1364 (void) printf("dc_cmd: exited with rv %d, errno(%d):%s\n",
1365 rv
, errno
, strerror(errno
));
1369 free(iocdata
.nvl_user
);