4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/errno.h>
30 #include <sys/cmn_err.h>
31 #include <sys/param.h>
32 #include <sys/modctl.h>
36 #include <sys/clock.h>
38 #include <sys/todio.h>
40 #include <sys/sunddi.h>
44 #define getsoftc(minor) \
45 ((struct tod_softc *)ddi_get_soft_state(statep, (minor)))
47 /* dev_ops and cb_ops entry point function declarations */
49 static int tod_attach(dev_info_t
*, ddi_attach_cmd_t
);
50 static int tod_detach(dev_info_t
*, ddi_detach_cmd_t
);
51 static int tod_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
53 static int tod_open(dev_t
*, int, int, cred_t
*);
54 static int tod_close(dev_t
, int, int, cred_t
*);
55 static int tod_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
57 struct cb_ops tod_cb_ops
= {
68 ddi_segmap
, /* segmap */
71 NULL
, /* for STREAMS drivers */
72 D_NEW
| D_MP
/* driver compatibility flag */
75 static struct dev_ops tod_dev_ops
= {
76 DEVO_REV
, /* driver build version */
77 0, /* device reference count */
85 (struct bus_ops
*)NULL
,
87 ddi_quiesce_not_supported
, /* devo_quiesce */
90 /* module configuration stuff */
92 extern struct mod_ops mod_driverops
;
94 static struct modldrv modldrv
= {
100 static struct modlinkage modlinkage
= {
112 if (e
= ddi_soft_state_init(&statep
, sizeof (struct tod_softc
), 1)) {
116 if ((e
= mod_install(&modlinkage
)) != 0) {
117 ddi_soft_state_fini(&statep
);
129 if ((e
= mod_remove(&modlinkage
)) != 0) {
133 ddi_soft_state_fini(&statep
);
135 return (DDI_SUCCESS
);
140 _info(struct modinfo
*modinfop
)
142 return (mod_info(&modlinkage
, modinfop
));
148 tod_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
150 int inst
= getminor((dev_t
)arg
);
151 int retval
= DDI_SUCCESS
;
152 struct tod_softc
*softc
;
156 case DDI_INFO_DEVT2DEVINFO
:
157 if ((softc
= getsoftc(inst
)) == NULL
) {
158 *result
= (void *)NULL
;
159 retval
= DDI_FAILURE
;
161 *result
= (void *)softc
->dip
;
165 case DDI_INFO_DEVT2INSTANCE
:
166 *result
= (void *)(uintptr_t)inst
;
170 retval
= DDI_FAILURE
;
177 tod_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
181 struct tod_softc
*softc
= NULL
;
187 inst
= ddi_get_instance(dip
);
189 * Create minor node. The minor device number, inst, has no
190 * meaning. The model number above, which will be added to
191 * the device's softc, is used to direct peculiar behavior.
193 (void) sprintf(name
, "tod%d", inst
);
194 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, inst
,
195 DDI_PSEUDO
, NULL
) == DDI_FAILURE
)
199 * Allocate a soft state structure for this instance.
201 if (ddi_soft_state_zalloc(statep
, inst
) != DDI_SUCCESS
)
204 softc
= getsoftc(inst
);
206 softc
->cpr_stage
= ~TOD_SUSPENDED
;
207 mutex_init(&softc
->mutex
, NULL
, MUTEX_DRIVER
, NULL
);
209 return (DDI_SUCCESS
);
212 inst
= ddi_get_instance(dip
);
213 softc
= getsoftc(inst
);
214 mutex_enter(&softc
->mutex
);
215 softc
->cpr_stage
= ~TOD_SUSPENDED
;
216 mutex_exit(&softc
->mutex
);
217 return (DDI_SUCCESS
);
220 return (DDI_FAILURE
);
224 /* Free soft state, if allocated. remove minor node if added earlier */
226 ddi_soft_state_free(statep
, inst
);
228 ddi_remove_minor_node(dip
, NULL
);
230 return (DDI_FAILURE
);
234 tod_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
237 struct tod_softc
*softc
;
242 inst
= ddi_get_instance(dip
);
243 if ((softc
= getsoftc(inst
)) == NULL
)
246 * Free the soft state and remove minor node added earlier.
248 mutex_destroy(&softc
->mutex
);
249 ddi_soft_state_free(statep
, inst
);
250 ddi_remove_minor_node(dip
, NULL
);
251 return (DDI_SUCCESS
);
254 inst
= ddi_get_instance(dip
);
255 softc
= getsoftc(inst
);
256 mutex_enter(&softc
->mutex
);
257 softc
->cpr_stage
= TOD_SUSPENDED
;
258 mutex_exit(&softc
->mutex
);
259 return (DDI_SUCCESS
);
262 return (DDI_FAILURE
);
269 tod_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*credp
)
271 int inst
= getminor(*devp
);
273 return (getsoftc(inst
) == NULL
? ENXIO
: 0);
279 tod_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
281 int inst
= getminor(dev
);
283 return (getsoftc(inst
) == NULL
? ENXIO
: 0);
289 tod_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
, int *rvalp
)
291 int inst
= getminor(dev
);
292 struct tod_softc
*softc
;
295 if ((softc
= getsoftc(inst
)) == NULL
)
298 mutex_enter(&softc
->mutex
);
299 while (softc
->cpr_stage
== TOD_SUSPENDED
) {
300 mutex_exit(&softc
->mutex
);
301 (void) ddi_dev_is_needed(softc
->dip
, 0, 1);
302 mutex_enter(&softc
->mutex
);
307 case TOD_CLEAR_ALARM
:
308 mutex_enter(&tod_lock
);
309 tod_ops
.tod_clear_power_alarm();
310 mutex_exit(&tod_lock
);
314 if ((mode
& FMODELS
) == FNATIVE
) {
315 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ts
.tv_sec
,
316 sizeof (ts
.tv_sec
), mode
) != 0) {
317 mutex_exit(&softc
->mutex
);
323 if (ddi_copyin((caddr_t
)arg
,
324 &time32
, sizeof (time32
), mode
) != 0) {
325 mutex_exit(&softc
->mutex
);
328 ts
.tv_sec
= (time_t)time32
;
332 mutex_enter(&tod_lock
);
333 tod_ops
.tod_set_power_alarm(ts
);
334 mutex_exit(&tod_lock
);
338 mutex_enter(&tod_lock
);
339 ts
= tod_ops
.tod_get();
340 mutex_exit(&tod_lock
);
342 if ((mode
& FMODELS
) == FNATIVE
) {
343 if (ddi_copyout((caddr_t
)&ts
.tv_sec
, (caddr_t
)arg
,
344 sizeof (ts
.tv_sec
), mode
) != 0) {
345 mutex_exit(&softc
->mutex
);
351 if (TIMEVAL_OVERFLOW(&ts
)) {
352 mutex_exit(&softc
->mutex
);
356 time32
= (time32_t
)ts
.tv_sec
;
357 if (ddi_copyout(&time32
,
358 (caddr_t
)arg
, sizeof (time32
), mode
) != 0) {
359 mutex_exit(&softc
->mutex
);
366 mutex_exit(&softc
->mutex
);
370 mutex_exit(&softc
->mutex
);