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 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/param.h>
40 #include <sys/nvpair.h>
41 #include "libdevice.h"
43 static int _libdevice_debug
= 0;
44 static const char *devctl_minorname
= ":devctl";
45 static const char *nullptr = "<null>";
46 static const char *devctl_target_raw
= "a,raw";
48 typedef enum { DEVCTL_BUS
, DEVCTL_DEVICE
, DEVCTL_AP
, DEVCTL_CLONE
,
49 DEVCTL_PM_DEV
, DEVCTL_PM_BUS
} dc_type_t
;
52 * devctl_hdl structures are allocated by the devctl_XX_acquire()
53 * interfaces and passed to the remaining interfaces in this library.
56 char *opath
; /* copy of the original path */
57 dc_type_t hdltype
; /* handle type */
58 int fd
; /* nexus device node */
59 char *nodename
; /* DEVCTL_DEVICE handles only */
60 char *unitaddr
; /* DEVCTL_DEVICE handles only */
62 #define DCP(x) ((struct devctl_hdl *)(x))
64 static int dc_cmd(uint_t
, uint_t
, struct devctl_hdl
*, nvlist_t
*, void *);
65 static devctl_hdl_t
dc_mkhndl(dc_type_t
, char *, uint_t
, devctl_hdl_t
);
68 #pragma init(_libdevice_init)
72 _libdevice_debug
= getenv("LIBDEVICE_DEBUG") != NULL
;
76 * release a devctl_hdl structure
79 devctl_release(devctl_hdl_t hdl
)
82 (void) printf("devctl_release: %p\n", (void *)hdl
);
87 if (DCP(hdl
)->fd
!= -1)
88 (void) close(DCP(hdl
)->fd
);
90 if (DCP(hdl
)->opath
!= NULL
)
91 free(DCP(hdl
)->opath
);
93 if (DCP(hdl
)->nodename
!= NULL
)
94 free(DCP(hdl
)->nodename
);
96 if (DCP(hdl
)->unitaddr
!= NULL
)
97 free(DCP(hdl
)->unitaddr
);
103 * construct a handle suitable for devctl_bus_*() operations
106 devctl_bus_acquire(char *devfs_path
, uint_t flags
)
110 if (_libdevice_debug
)
111 (void) printf("devctl_bus_acquire: %s (%d)\n",
112 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
114 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
119 oflags
= ((flags
& DC_EXCL
) != 0) ? O_EXCL
|O_RDWR
: O_RDWR
;
120 return (dc_mkhndl(DEVCTL_BUS
, devfs_path
, oflags
, NULL
));
125 * construct a handle suitable for devctl_bus_*() and
126 * devctl_device_*() operations.
129 devctl_device_acquire(char *devfs_path
, uint_t flags
)
133 if (_libdevice_debug
)
134 (void) printf("devctl_device_acquire: %s (%d)\n",
135 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
137 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
142 oflags
= ((flags
& DC_EXCL
) != 0) ? O_EXCL
|O_RDWR
: O_RDWR
;
143 return (dc_mkhndl(DEVCTL_DEVICE
, devfs_path
, oflags
, NULL
));
148 * given a devfs (/devices) pathname to an attachment point device,
149 * access the device and return a handle to be passed to the
150 * devctl_ap_XXX() functions.
153 devctl_ap_acquire(char *devfs_path
, uint_t flags
)
157 if (_libdevice_debug
)
158 (void) printf("devctl_ap_acquire: %s (%d)\n",
159 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
161 if ((devfs_path
== NULL
) ||
162 ((flags
!= 0) && ((flags
& DC_EXCL
) != 0) &&
163 ((flags
& DC_RDONLY
) != 0))) {
168 oflags
= ((flags
& DC_EXCL
) != 0) ? O_EXCL
: 0;
169 oflags
|= ((flags
& DC_RDONLY
) != 0) ? O_RDONLY
: O_RDWR
;
171 return (dc_mkhndl(DEVCTL_AP
, devfs_path
, oflags
, NULL
));
176 * given a devfs (/devices) pathname access the device and return
177 * a handle to be passed to the devctl_pm_XXX() functions.
178 * The minor name ":devctl" is appended.
181 devctl_pm_bus_acquire(char *devfs_path
, uint_t flags
)
185 if (_libdevice_debug
)
186 (void) printf("devctl_pm_bus_acquire: %s (%d)\n",
187 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
189 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
194 oflags
= ((flags
& DC_EXCL
) != 0) ? (O_EXCL
| O_RDWR
) : O_RDWR
;
195 return (dc_mkhndl(DEVCTL_PM_BUS
, devfs_path
, oflags
, NULL
));
200 * given a devfs (/devices) pathname access the device and return
201 * a handle to be passed to the devctl_pm_XXX() functions.
202 * The minor name is derived from the device name.
205 devctl_pm_dev_acquire(char *devfs_path
, uint_t flags
)
209 if (_libdevice_debug
)
210 (void) printf("devctl_pm_dev_acquire: %s (%d)\n",
211 ((devfs_path
!= NULL
) ? devfs_path
: nullptr), flags
);
213 if ((devfs_path
== NULL
) || ((flags
!= 0) && (flags
!= DC_EXCL
))) {
218 oflags
= ((flags
& DC_EXCL
) != 0) ? (O_EXCL
| O_RDWR
) : O_RDWR
;
219 return (dc_mkhndl(DEVCTL_PM_DEV
, devfs_path
, oflags
, NULL
));
224 * allocate and initalize the devctl_hdl structure for the
225 * particular handle type.
228 dc_mkhndl(dc_type_t type
, char *path
, uint_t oflags
, devctl_hdl_t pc
)
230 struct devctl_hdl
*dcp
;
232 char iocpath
[MAXPATHLEN
];
233 char *nodename
, *unitsep
, *minorsep
, *chop
;
239 if ((path
== NULL
) || (strlen(path
) > MAXPATHLEN
- 1)) {
245 * allocate handle and make a copy of the original path
247 if ((dcp
= calloc(1, sizeof (*dcp
))) == NULL
) {
251 if ((dcp
->opath
= strdup(path
)) == NULL
) {
252 devctl_release((devctl_hdl_t
)dcp
);
257 (void) strcpy(iocpath
, path
);
262 * break apart the pathname according to the type handle
267 * chop off any minor name and concatenate the
268 * ":devctl" minor node name string.
270 if ((chop
= strrchr(iocpath
, ':')) != NULL
)
273 if (strlcat(iocpath
, devctl_minorname
, MAXPATHLEN
) >=
275 devctl_release((devctl_hdl_t
)dcp
);
278 } else if (_libdevice_debug
) {
279 (void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath
);
285 * Chop up the last device component in the pathname.
286 * Concatenate either the device name itself, or the
287 * "a,raw" string, as the minor node name, to the iocpath.
289 if ((iocpath_dup
= strdup(iocpath
)) == NULL
) {
290 devctl_release((devctl_hdl_t
)dcp
);
294 if ((chop
= strrchr(iocpath_dup
, '/')) == NULL
) {
295 devctl_release((devctl_hdl_t
)dcp
);
303 * remove the "@0,0" string
305 tok
= strtok(nodename
, "@");
306 if ((minorname
= malloc(strlen(tok
) +1)) == NULL
) {
307 if (_libdevice_debug
)
308 (void) printf("DEVCTL_PM_DEV: failed malloc for"
310 devctl_release((devctl_hdl_t
)dcp
);
314 (void) strcpy(minorname
, tok
);
315 if (_libdevice_debug
) {
316 (void) printf("DEVCTL_PM_DEV: minorname %s\n",
321 * construct the name of the ioctl device
322 * by concatenating either ":a,raw" or ":"minorname
324 (void) strlcat(iocpath
, ":", MAXPATHLEN
);
325 if (strcmp(minorname
, "disk_chan") == 0 ||
326 strcmp(minorname
, "disk_wwn") == 0 ||
327 strcmp(minorname
, "disk_cdrom") == 0) {
328 strlcpy_size
= strlcat(iocpath
, devctl_target_raw
,
331 strlcpy_size
= strlcat(iocpath
, minorname
, MAXPATHLEN
);
333 if (strlcpy_size
>= MAXPATHLEN
) {
334 devctl_release((devctl_hdl_t
)dcp
);
337 } else if (_libdevice_debug
) {
338 (void) printf("DEVCTL_PM_DEV: iocpath %s\n",
345 * take the pathname as provided.
351 * chop off any minor name and concatenate the
352 * ":devctl" minor node name string.
354 if ((chop
= strrchr(iocpath
, ':')) != NULL
)
357 if (strlcat(iocpath
, devctl_minorname
, MAXPATHLEN
) >=
359 devctl_release((devctl_hdl_t
)dcp
);
367 * create a device handle for a new device created
368 * from a call to devctl_bus_dev_create()
370 dcp
->hdltype
= DEVCTL_DEVICE
;
377 * Chop up the last device component in the pathname.
378 * The componets are passed as nodename and unitaddr
379 * in the IOCTL data for DEVCTL ops on devices.
381 if ((chop
= strrchr(iocpath
, '/')) == NULL
) {
382 devctl_release((devctl_hdl_t
)dcp
);
389 unitsep
= strchr(nodename
, '@');
390 minorsep
= strchr(nodename
, ':');
392 if (unitsep
== NULL
) {
393 devctl_release((devctl_hdl_t
)dcp
);
399 * copy the nodename and unit address
401 if (((dcp
->nodename
= malloc(MAXNAMELEN
)) == NULL
) ||
402 ((dcp
->unitaddr
= malloc(MAXNAMELEN
)) == NULL
)) {
403 devctl_release((devctl_hdl_t
)dcp
);
408 if (minorsep
!= NULL
)
410 (void) snprintf(dcp
->nodename
, MAXNAMELEN
, "%s", nodename
);
411 (void) snprintf(dcp
->unitaddr
, MAXNAMELEN
, "%s", unitsep
+1);
414 * construct the name of the ioctl device
416 if (strlcat(iocpath
, devctl_minorname
, MAXPATHLEN
) >=
418 devctl_release((devctl_hdl_t
)dcp
);
425 devctl_release((devctl_hdl_t
)dcp
);
430 if (_libdevice_debug
)
431 (void) printf("dc_mkhndl: iocpath %s ", iocpath
);
434 * verify the devctl or ap device exists and is a
435 * character device interface.
437 if (stat(iocpath
, &sb
) == 0) {
438 if ((sb
.st_mode
& S_IFMT
) != S_IFCHR
) {
439 if (_libdevice_debug
)
440 (void) printf(" - not character device\n");
442 devctl_release((devctl_hdl_t
)dcp
);
447 * return failure with errno value set by stat
449 if (_libdevice_debug
)
450 (void) printf(" - stat failed\n");
451 devctl_release((devctl_hdl_t
)dcp
);
456 * if this was a new device, dup the parents handle, otherwise
457 * just open the device.
459 if (type
== DEVCTL_CLONE
)
460 dcp
->fd
= dup(DCP(pc
)->fd
);
462 dcp
->fd
= open(iocpath
, oflags
);
465 if (_libdevice_debug
)
466 (void) printf(" - open/dup failed %d\n", errno
);
468 * leave errno as set by open/dup
470 devctl_release((devctl_hdl_t
)dcp
);
474 if (_libdevice_debug
)
475 (void) printf(" - open success\n");
477 return ((devctl_hdl_t
)dcp
);
481 * Power up component 0, to level MAXPWR, via a pm_raise_power() call
484 devctl_pm_raisepower(devctl_hdl_t dcp
)
488 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
489 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
494 rv
= dc_cmd(DEVCTL_PM_RAISE_PWR
, 0, DCP(dcp
), NULL
, NULL
);
496 if (_libdevice_debug
)
497 (void) printf("devctl_pm_raisepower: %d\n", rv
);
503 * Power up component 0, to level MAXPWR, via a power_has_changed() call
506 devctl_pm_changepowerhigh(devctl_hdl_t dcp
)
510 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
511 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
516 rv
= dc_cmd(DEVCTL_PM_CHANGE_PWR_HIGH
, 0, DCP(dcp
), NULL
, NULL
);
518 if (_libdevice_debug
)
519 (void) printf("devctl_pm_changepowerhigh: %d\n", rv
);
525 * Power down component 0, to level 0, via a pm_change_power() call
528 devctl_pm_changepowerlow(devctl_hdl_t dcp
)
532 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
533 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
538 rv
= dc_cmd(DEVCTL_PM_CHANGE_PWR_LOW
, 0, DCP(dcp
), NULL
, NULL
);
540 if (_libdevice_debug
)
541 (void) printf("devctl_pm_changepowerlow: %d\n", rv
);
547 * mark component 0 idle
550 devctl_pm_idlecomponent(devctl_hdl_t dcp
)
554 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
555 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
560 rv
= dc_cmd(DEVCTL_PM_IDLE_COMP
, 0, DCP(dcp
), NULL
, NULL
);
562 if (_libdevice_debug
)
563 (void) printf("devctl_pm_idlecomponent: %d\n", rv
);
569 * mark component 0 busy
572 devctl_pm_busycomponent(devctl_hdl_t dcp
)
576 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
577 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
582 rv
= dc_cmd(DEVCTL_PM_BUSY_COMP
, 0, DCP(dcp
), NULL
, NULL
);
584 if (_libdevice_debug
)
585 (void) printf("devctl_pm_busycomponent: %d\n", rv
);
594 devctl_pm_testbusy(devctl_hdl_t dcp
, uint_t
*busystate
)
597 uint_t busy_state
= 0;
599 if (busystate
== NULL
) {
604 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
605 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
610 rv
= dc_cmd(DEVCTL_PM_BUSY_COMP_TEST
, 0, DCP(dcp
), NULL
,
611 (void *)&busy_state
);
616 *busystate
= busy_state
;
618 if (_libdevice_debug
)
619 (void) printf("devctl_pm_bus_testbusy: rv %d busystate %x\n",
626 * set flag to fail DDI_SUSPEND
629 devctl_pm_failsuspend(devctl_hdl_t dcp
)
633 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
634 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
639 rv
= dc_cmd(DEVCTL_PM_FAIL_SUSPEND
, 0, DCP(dcp
), NULL
, NULL
);
641 if (_libdevice_debug
)
642 (void) printf("devctl_pm_failsuspend: %d\n", rv
);
647 devctl_pm_bus_teststrict(devctl_hdl_t dcp
, uint_t
*strict
)
652 if (strict
== NULL
) {
657 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
662 rv
= dc_cmd(DEVCTL_PM_BUS_STRICT_TEST
, 0, DCP(dcp
), NULL
,
663 (void *)&strict_state
);
668 *strict
= strict_state
;
670 if (_libdevice_debug
)
671 (void) printf("devctl_pm_bus_teststrict: rv %d strict %x\n",
678 * issue prom_printf() call
681 devctl_pm_device_promprintf(devctl_hdl_t dcp
)
685 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
686 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
691 rv
= dc_cmd(DEVCTL_PM_PROM_PRINTF
, 0, DCP(dcp
), NULL
, NULL
);
693 if (_libdevice_debug
)
694 (void) printf("devctl_pm_device_promprintf: %d\n", rv
);
699 * set flag to power up the device via
700 * pm_power_has_changed() calls vs.
701 * pm_raise_power(), during DDI_RESUME
704 devctl_pm_device_changeonresume(devctl_hdl_t dcp
)
708 if (dcp
== NULL
|| (DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
&&
709 DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
)) {
714 rv
= dc_cmd(DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME
, 0,
715 DCP(dcp
), NULL
, NULL
);
717 if (_libdevice_debug
)
718 (void) printf("devctl_pm_device_changeonresume: %d\n", rv
);
723 * issue DEVCTL_PM_NO_LOWER_POWER to clear the LOWER_POWER_FLAG
724 * flag: pm_lower_power() will not be called on device detach
727 devctl_pm_device_no_lower_power(devctl_hdl_t dcp
)
731 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_PM_DEV
) {
736 rv
= dc_cmd(DEVCTL_PM_NO_LOWER_POWER
, 0, DCP(dcp
), NULL
, NULL
);
738 if (_libdevice_debug
)
739 (void) printf("devctl_pm_device_no_lower_power: %d\n", rv
);
744 * issue DEVCTL_PM_BUS_NO_INVOL ioctl to set the NO_INVOL_FLAG
745 * flag: parent driver will mark itself idle twice in
746 * DDI_CTLOPS_DETACH(POST)
749 devctl_pm_bus_no_invol(devctl_hdl_t dcp
)
753 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_PM_BUS
) {
758 rv
= dc_cmd(DEVCTL_PM_BUS_NO_INVOL
, 0, DCP(dcp
), NULL
, NULL
);
760 if (_libdevice_debug
)
761 (void) printf("devctl_pm_bus_no_invol: %d\n", rv
);
766 * Place the device ONLINE
769 devctl_device_online(devctl_hdl_t dcp
)
773 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_DEVICE
) {
778 rv
= dc_cmd(DEVCTL_DEVICE_ONLINE
, 0, DCP(dcp
), NULL
, NULL
);
780 if (_libdevice_debug
)
781 (void) printf("devctl_device_online: %d\n", rv
);
787 * take device OFFLINE
790 devctl_device_offline(devctl_hdl_t dcp
)
794 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_DEVICE
) {
799 rv
= dc_cmd(DEVCTL_DEVICE_OFFLINE
, 0, DCP(dcp
), NULL
, NULL
);
801 if (_libdevice_debug
)
802 (void) printf("devctl_device_offline: %d\n", rv
);
808 * take the device OFFLINE and remove its dev_info node
811 devctl_device_remove(devctl_hdl_t dcp
)
815 if (dcp
== NULL
|| DCP(dcp
)->hdltype
!= DEVCTL_DEVICE
) {
820 rv
= dc_cmd(DEVCTL_DEVICE_REMOVE
, 0, DCP(dcp
), NULL
, NULL
);
822 if (_libdevice_debug
)
823 (void) printf("devctl_device_remove: %d\n", rv
);
833 devctl_bus_quiesce(devctl_hdl_t dcp
)
837 rv
= dc_cmd(DEVCTL_BUS_QUIESCE
, 0, DCP(dcp
), NULL
, NULL
);
839 if (_libdevice_debug
)
840 (void) printf("devctl_bus_quiesce: %d\n", rv
);
846 devctl_bus_unquiesce(devctl_hdl_t dcp
)
850 rv
= dc_cmd(DEVCTL_BUS_UNQUIESCE
, 0, DCP(dcp
), NULL
, NULL
);
852 if (_libdevice_debug
)
853 (void) printf("devctl_bus_unquiesce: %d\n", rv
);
859 devctl_bus_reset(devctl_hdl_t dcp
)
863 rv
= dc_cmd(DEVCTL_BUS_RESET
, 0, DCP(dcp
), NULL
, NULL
);
865 if (_libdevice_debug
)
866 (void) printf("devctl_bus_reset: %d\n", rv
);
872 devctl_bus_resetall(devctl_hdl_t dcp
)
876 rv
= dc_cmd(DEVCTL_BUS_RESETALL
, 0, DCP(dcp
), NULL
, NULL
);
878 if (_libdevice_debug
)
879 (void) printf("devctl_bus_resetall: %d\n", rv
);
885 devctl_device_reset(devctl_hdl_t dcp
)
889 rv
= dc_cmd(DEVCTL_DEVICE_RESET
, 0, DCP(dcp
), NULL
, NULL
);
891 if (_libdevice_debug
)
892 (void) printf("devctl_device_reset: %d\n", rv
);
898 devctl_device_getstate(devctl_hdl_t dcp
, uint_t
*devstate
)
903 if (devstate
== NULL
) {
908 rv
= dc_cmd(DEVCTL_DEVICE_GETSTATE
, 0, DCP(dcp
), NULL
,
909 (void *)&device_state
);
914 *devstate
= device_state
;
916 if (_libdevice_debug
)
917 (void) printf("devctl_device_getstate: rv %d state %x\n",
924 devctl_bus_getstate(devctl_hdl_t dcp
, uint_t
*devstate
)
929 if (devstate
== NULL
) {
934 rv
= dc_cmd(DEVCTL_BUS_GETSTATE
, 0, DCP(dcp
), NULL
,
935 (void *)&device_state
);
940 *devstate
= device_state
;
942 if (_libdevice_debug
)
943 (void) printf("devctl_bus_getstate: rv %d, state %x\n",
950 devctl_bus_configure(devctl_hdl_t dcp
)
954 rv
= dc_cmd(DEVCTL_BUS_CONFIGURE
, 0, DCP(dcp
), NULL
, NULL
);
956 if (_libdevice_debug
)
957 (void) printf("devctl_bus_configure: %d\n", rv
);
963 devctl_bus_unconfigure(devctl_hdl_t dcp
)
967 rv
= dc_cmd(DEVCTL_BUS_UNCONFIGURE
, 0, DCP(dcp
), NULL
, NULL
);
969 if (_libdevice_debug
)
970 (void) printf("devctl_bus_unconfigure: %d\n", rv
);
976 * devctl_bus_dev_create() - create a new child device
977 * Attempt to construct and attach a new child device below a
978 * bus nexus (dcp). The device is defined using the devctl_ddef_*()
979 * routines to specify the set of bus-specific properties required
980 * to initalize and attach the device.
983 devctl_bus_dev_create(devctl_hdl_t dcp
, devctl_ddef_t ddef_hdl
,
984 uint_t flags
, devctl_hdl_t
*new_dcp
)
986 char devname
[MAXNAMELEN
];
987 char devpath
[MAXPATHLEN
];
990 if (dcp
== NULL
|| ddef_hdl
== NULL
) {
995 (void) memset(devname
, 0, sizeof (devname
));
996 rv
= dc_cmd(DEVCTL_BUS_DEV_CREATE
, flags
, DCP(dcp
),
997 (nvlist_t
*)ddef_hdl
, devname
);
1000 * construct a device handle for the new device
1002 if ((rv
== 0) && (new_dcp
!= NULL
)) {
1003 char *minorname
, *lastslash
;
1005 (void) memset(devpath
, 0, sizeof (devpath
));
1006 (void) strcat(devpath
, DCP(dcp
)->opath
);
1009 * Take the pathname of the parent device, chop off
1010 * any minor name info, and append the name@addr of
1011 * the new child device.
1012 * Call dc_mkhndl() with this constructed path and
1013 * the CLONE handle type to create a new handle which
1014 * references the new child device.
1016 lastslash
= strrchr(devpath
, '/');
1017 if (*(lastslash
+ 1) == '\0') {
1020 if ((minorname
= strchr(lastslash
, ':')) != NULL
)
1023 (void) strcat(devpath
, "/");
1024 (void) strlcat(devpath
, devname
, MAXPATHLEN
);
1025 *new_dcp
= dc_mkhndl(DEVCTL_CLONE
, devpath
, 0, dcp
);
1026 if (*new_dcp
== NULL
)
1034 devctl_ap_connect(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1038 rv
= dc_cmd(DEVCTL_AP_CONNECT
, 0, DCP(dcp
), ap_data
, NULL
);
1040 if (_libdevice_debug
)
1041 (void) printf("devctl_ap_connect: %d\n", rv
);
1047 devctl_ap_disconnect(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1051 rv
= dc_cmd(DEVCTL_AP_DISCONNECT
, 0, DCP(dcp
), ap_data
, NULL
);
1053 if (_libdevice_debug
)
1054 (void) printf("devctl_ap_disconnect: %d\n", rv
);
1060 devctl_ap_insert(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1064 rv
= dc_cmd(DEVCTL_AP_INSERT
, 0, DCP(dcp
), ap_data
, NULL
);
1066 if (_libdevice_debug
)
1067 (void) printf("devctl_ap_insert: %d\n", rv
);
1073 devctl_ap_remove(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1077 rv
= dc_cmd(DEVCTL_AP_REMOVE
, 0, DCP(dcp
), ap_data
, NULL
);
1079 if (_libdevice_debug
)
1080 (void) printf("devctl_ap_remove: %d\n", rv
);
1086 devctl_ap_configure(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1090 rv
= dc_cmd(DEVCTL_AP_CONFIGURE
, 0, DCP(dcp
), ap_data
, NULL
);
1092 if (_libdevice_debug
)
1093 (void) printf("devctl_ap_configure: %d\n", rv
);
1099 devctl_ap_unconfigure(devctl_hdl_t dcp
, nvlist_t
*ap_data
)
1103 rv
= dc_cmd(DEVCTL_AP_UNCONFIGURE
, 0, DCP(dcp
), ap_data
, NULL
);
1105 if (_libdevice_debug
)
1106 (void) printf("devctl_ap_unconfigure: %d\n", rv
);
1112 devctl_ap_getstate(devctl_hdl_t dcp
, nvlist_t
*ap_data
,
1113 devctl_ap_state_t
*apstate
)
1116 devctl_ap_state_t ap_state
;
1118 rv
= dc_cmd(DEVCTL_AP_GETSTATE
, 0, DCP(dcp
), ap_data
,
1122 (void) memset(apstate
, 0, sizeof (struct devctl_ap_state
));
1124 *apstate
= ap_state
;
1126 if (_libdevice_debug
)
1127 (void) printf("devctl_ap_getstate: %d\n", rv
);
1133 * Allocate a device 'definition' handle, in reality a list of
1138 devctl_ddef_alloc(char *nodename
, int flags
)
1143 if ((nodename
== NULL
) || *nodename
== '\0') {
1149 * allocate nvlist structure which is returned as an
1150 * opaque handle to the caller. If this fails, return
1151 * NULL with errno left set to the value
1153 if (nvlist_alloc(&nvlp
, NV_UNIQUE_NAME_TYPE
, 0) != 0) {
1159 * add the nodename of the new device to the list
1161 if (nvlist_add_string(nvlp
, DC_DEVI_NODENAME
, nodename
) != 0) {
1167 if (_libdevice_debug
)
1168 (void) printf("devctl_ddef_alloc: node %s nvp %p\n", nodename
,
1171 return ((devctl_ddef_t
)nvlp
);
1175 * free the definition handle
1178 devctl_ddef_free(devctl_ddef_t ddef_hdl
)
1180 if (_libdevice_debug
)
1181 (void) printf("devctl_ddef_free: nvp %p\n", (void *)ddef_hdl
);
1183 if (ddef_hdl
!= NULL
) {
1184 nvlist_free((nvlist_t
*)ddef_hdl
);
1189 * define an integer property
1192 devctl_ddef_int(devctl_ddef_t ddef_hdl
, char *name
, int32_t value
)
1197 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1202 rv
= nvlist_add_int32((nvlist_t
*)ddef_hdl
, name
, value
);
1204 if (_libdevice_debug
)
1205 (void) printf("devctl_ddef_int: rv %d nvp %p name %s val %d\n",
1206 rv
, (void *)ddef_hdl
, name
, value
);
1212 * define an integer array property
1215 devctl_ddef_int_array(devctl_ddef_t ddef_hdl
, char *name
, int nelements
,
1220 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1225 rv
= nvlist_add_int32_array((nvlist_t
*)ddef_hdl
, name
, value
,
1228 if (_libdevice_debug
) {
1229 (void) printf("devctl_ddef_int_array: rv %d nvp %p name %s: ",
1230 rv
, (void *)ddef_hdl
, name
);
1231 for (i
= 0; i
< nelements
; i
++)
1232 (void) printf("0x%x ", value
[i
]);
1233 (void) printf("\n");
1240 * define a string property
1243 devctl_ddef_string(devctl_ddef_t ddef_hdl
, char *name
, char *value
)
1247 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1252 rv
= nvlist_add_string((nvlist_t
*)ddef_hdl
, name
, value
);
1254 if (_libdevice_debug
)
1255 (void) printf("devctl_ddef_string: rv %d nvp %p %s=\"%s\"\n",
1256 rv
, (void *)ddef_hdl
, name
, value
);
1262 * define a string array property
1265 devctl_ddef_string_array(devctl_ddef_t ddef_hdl
, char *name
, int nelements
,
1270 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1275 rv
= nvlist_add_string_array((nvlist_t
*)ddef_hdl
, name
,
1278 if (_libdevice_debug
) {
1279 (void) printf("devctl_ddef_string_array: rv %d nvp %p "
1280 "name %s:\n", rv
, (void *)ddef_hdl
, name
);
1281 for (i
= 0; i
< nelements
; i
++)
1282 (void) printf("\t%d: \"%s\"\n", i
, value
[i
]);
1288 * define a byte array property
1291 devctl_ddef_byte_array(devctl_ddef_t ddef_hdl
, char *name
, int nelements
,
1296 if (ddef_hdl
== NULL
|| name
== NULL
|| *name
== '\0') {
1301 rv
= nvlist_add_byte_array((nvlist_t
*)ddef_hdl
, name
, value
,
1308 * return the pathname which was used to acquire the handle
1311 devctl_get_pathname(devctl_hdl_t dcp
, char *pathbuf
, size_t bufsz
)
1313 if (dcp
== NULL
|| pathbuf
== NULL
|| bufsz
== 0) {
1318 (void) snprintf(pathbuf
, bufsz
, "%s", DCP(dcp
)->opath
);
1324 * execute the IOCTL request
1327 dc_cmd(uint_t cmd
, uint_t flags
, struct devctl_hdl
*dcp
, nvlist_t
*ulp
,
1330 struct devctl_iocdata iocdata
;
1333 if (_libdevice_debug
)
1334 (void) printf("dc_cmd: %x dcp %p ulp %p flags %x rv %p\n", cmd
,
1335 (void *)dcp
, (void *)ulp
, flags
, retinfo
);
1337 if ((dcp
== NULL
) || (DCP(dcp
)->fd
== -1)) {
1342 (void) memset(&iocdata
, 0, sizeof (struct devctl_iocdata
));
1345 * if there was any user supplied data in the form of a nvlist,
1346 * pack the list prior to copyin.
1349 if (rv
= nvlist_pack(ulp
, (char **)&iocdata
.nvl_user
,
1350 &iocdata
.nvl_usersz
, NV_ENCODE_NATIVE
, 0)) {
1352 * exit with errno set by nvlist_pack()
1357 iocdata
.nvl_user
= NULL
;
1358 iocdata
.nvl_usersz
= 0;
1362 * finish initalizing the request and execute the IOCTL
1365 iocdata
.flags
= flags
;
1366 iocdata
.c_nodename
= dcp
->nodename
;
1367 iocdata
.c_unitaddr
= dcp
->unitaddr
;
1368 iocdata
.cpyout_buf
= retinfo
;
1369 rv
= ioctl(dcp
->fd
, cmd
, &iocdata
);
1370 if (rv
< 0 && _libdevice_debug
) {
1371 (void) printf("dc_cmd: exited with rv %d, errno(%d):%s\n",
1372 rv
, errno
, strerror(errno
));
1376 if (iocdata
.nvl_user
!= NULL
)
1377 free(iocdata
.nvl_user
);