summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/kb8042/kb8042.c
diff options
context:
space:
mode:
authorrandyf <none@none>2007-10-20 16:00:42 -0700
committerrandyf <none@none>2007-10-20 16:00:42 -0700
commit2df1fe9ca32bb227b9158c67f5c00b54c20b10fd (patch)
tree358c576f885c00d42a760d9e35e5b66e77209fe2 /usr/src/uts/common/io/kb8042/kb8042.c
parent10b3fbf593a6678eec9b50a01903ef4eb73111e4 (diff)
downloadillumos-gate-2df1fe9ca32bb227b9158c67f5c00b54c20b10fd.tar.gz
PSARC/2005/469 X86 Energy Star compliance
PSARC/2006/632 PSMI extension for state save and restore 6330209 nge needs to support DDI_SUSPEND/DDI_RESUME 6381827 Suspend to RAM on x86 6393154 audio810 needs to support DDI_SUSPEND/DDI_RESUME 6397047 fd, fdc needs to support Suspend/Resume 6401974 cannot enter S3 with ohci PME enable set on Tyan 2865 with Sun or Tyan 2.01 BIOS 6422613 memscrubber doesn't re-acquire lock before CALLB_CPR_EXIT 6455736 ata/dadk/cmdk should support DDI_SUSPEND/DDI_RESUME 6511370 CPR on SPARC regression 6586018 TODOP Macros in i86pc/sys/machclock.h not in sun4u/sun4v equivilent (Sparc only) 6610124 It takes more than 3 minutes after printing "pci_pre_resume nv_sata:0" 6617143 powerd/pmconfig emits a different default message for an existing on or off action. --HG-- rename : usr/src/cmd/power/power.conf => usr/src/cmd/power/power.conf.sparc
Diffstat (limited to 'usr/src/uts/common/io/kb8042/kb8042.c')
-rw-r--r--usr/src/uts/common/io/kb8042/kb8042.c90
1 files changed, 88 insertions, 2 deletions
diff --git a/usr/src/uts/common/io/kb8042/kb8042.c b/usr/src/uts/common/io/kb8042/kb8042.c
index 6799e6d75a..0e8369b076 100644
--- a/usr/src/uts/common/io/kb8042/kb8042.c
+++ b/usr/src/uts/common/io/kb8042/kb8042.c
@@ -431,6 +431,14 @@ kb8042_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
kb8042->w_init = 0;
kb8042_init(kb8042, B_TRUE);
kb8042_setled(kb8042, leds, B_FALSE);
+ mutex_enter(&kb8042->w_hw_mutex);
+ kb8042->suspended = B_FALSE;
+ if (kb8042->w_qp != NULL) {
+ enableok(WR(kb8042->w_qp));
+ qenable(WR(kb8042->w_qp));
+ }
+ cv_broadcast(&kb8042->suspend_cv);
+ mutex_exit(&kb8042->w_hw_mutex);
return (DDI_SUCCESS);
case DDI_ATTACH:
@@ -480,7 +488,8 @@ kb8042_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
}
mutex_init(&kb8042->w_hw_mutex, NULL, MUTEX_DRIVER, kb8042->w_iblock);
-
+ cv_init(&kb8042->ops_cv, NULL, CV_DRIVER, NULL);
+ cv_init(&kb8042->suspend_cv, NULL, CV_DRIVER, NULL);
kb8042->init_state |= KB8042_HW_MUTEX_INITTED;
kb8042_init(kb8042, B_FALSE);
@@ -552,6 +561,12 @@ kb8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
switch (cmd) {
case DDI_SUSPEND:
+ mutex_enter(&kb8042->w_hw_mutex);
+ ASSERT(kb8042->ops >= 0);
+ while (kb8042->ops > 0)
+ cv_wait(&kb8042->ops_cv, &kb8042->w_hw_mutex);
+ kb8042->suspended = B_TRUE;
+ mutex_exit(&kb8042->w_hw_mutex);
return (DDI_SUCCESS);
case DDI_DETACH:
@@ -606,8 +621,11 @@ kb8042_cleanup(struct kb8042 *kb8042)
{
ASSERT(kb8042_dip != NULL);
- if (kb8042->init_state & KB8042_HW_MUTEX_INITTED)
+ if (kb8042->init_state & KB8042_HW_MUTEX_INITTED) {
+ cv_destroy(&kb8042->suspend_cv);
+ cv_destroy(&kb8042->ops_cv);
mutex_destroy(&kb8042->w_hw_mutex);
+ }
if (kb8042->init_state & KB8042_INTR_ADDED)
ddi_remove_intr(kb8042_dip, 0, kb8042->w_iblock);
@@ -660,9 +678,19 @@ kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)
kb8042 = &Kdws;
+ mutex_enter(&kb8042->w_hw_mutex);
+ while (kb8042->suspended) {
+ if (cv_wait_sig(&kb8042->suspend_cv, &kb8042->w_hw_mutex) ==
+ 0) {
+ mutex_exit(&kb8042->w_hw_mutex);
+ return (EINTR);
+ }
+ }
+
kb8042->w_dev = *devp;
if (qp->q_ptr) {
+ mutex_exit(&kb8042->w_hw_mutex);
return (0);
}
qp->q_ptr = (caddr_t)kb8042;
@@ -670,6 +698,10 @@ kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)
if (!kb8042->w_qp)
kb8042->w_qp = qp;
+ ASSERT(kb8042->ops >= 0);
+ kb8042->ops++;
+ mutex_exit(&kb8042->w_hw_mutex);
+
kb8042_get_initial_leds(kb8042, &initial_leds, &initial_led_mask);
err = kbtrans_streams_init(qp, sflag, credp,
(struct kbtrans_hardware *)kb8042, &kb8042_callbacks,
@@ -700,6 +732,13 @@ kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)
kbtrans_streams_enable(kb8042->hw_kbtrans);
+ mutex_enter(&kb8042->w_hw_mutex);
+ ASSERT(kb8042->ops > 0);
+ kb8042->ops--;
+ if (kb8042->ops == 0)
+ cv_broadcast(&kb8042->ops_cv);
+ mutex_exit(&kb8042->w_hw_mutex);
+
return (0);
}
@@ -714,11 +753,31 @@ kb8042_close(queue_t *qp, int flag, cred_t *credp)
kb8042 = (struct kb8042 *)qp->q_ptr;
+ mutex_enter(&kb8042->w_hw_mutex);
+ while (kb8042->suspended) {
+ if (cv_wait_sig(&kb8042->suspend_cv, &kb8042->w_hw_mutex) ==
+ 0) {
+ mutex_exit(&kb8042->w_hw_mutex);
+ return (EINTR);
+ }
+ }
+
+ ASSERT(kb8042->ops >= 0);
+ kb8042->ops++;
+ mutex_exit(&kb8042->w_hw_mutex);
+
(void) kbtrans_streams_fini(kb8042->hw_kbtrans);
kb8042->w_qp = (queue_t *)NULL;
qprocsoff(qp);
+ mutex_enter(&kb8042->w_hw_mutex);
+ ASSERT(kb8042->ops > 0);
+ kb8042->ops--;
+ if (kb8042->ops == 0)
+ cv_broadcast(&kb8042->ops_cv);
+ mutex_exit(&kb8042->w_hw_mutex);
+
return (0);
}
@@ -728,10 +787,27 @@ kb8042_wsrv(queue_t *qp)
struct kb8042 *kb8042;
mblk_t *mp;
+ boolean_t suspended;
kb8042 = (struct kb8042 *)qp->q_ptr;
+ mutex_enter(&kb8042->w_hw_mutex);
+ suspended = kb8042->suspended;
+ ASSERT(kb8042->ops >= 0);
+ if (!suspended)
+ kb8042->ops++;
+ mutex_exit(&kb8042->w_hw_mutex);
+
+#ifdef NO_KB_DEBUG
+ while (!suspended && (mp = getq(qp)) != NULL) {
+#else
+ /*
+ * Not taking keyboard input while suspending can make debugging
+ * difficult. However, we still do the ops counting so that we
+ * don't suspend at a bad time.
+ */
while ((mp = getq(qp))) {
+#endif
switch (kbtrans_streams_message(kb8042->hw_kbtrans, mp)) {
case KBTRANS_MESSAGE_HANDLED:
continue;
@@ -765,6 +841,16 @@ kb8042_wsrv(queue_t *qp)
continue;
}
}
+
+ mutex_enter(&kb8042->w_hw_mutex);
+ if (!suspended) {
+ ASSERT(kb8042->ops > 0);
+ kb8042->ops--;
+ if (kb8042->ops == 0)
+ cv_broadcast(&kb8042->ops_cv);
+ }
+ mutex_exit(&kb8042->w_hw_mutex);
+
return (0);
}