1 /* $NetBSD: hpqlb_acpi.c,v 1.3 2009/09/25 20:26:59 dyoung Exp $ */
4 * Copyright (c) 2008 Christoph Egger <cegger@netbsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: hpqlb_acpi.c,v 1.3 2009/09/25 20:26:59 dyoung Exp $");
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/malloc.h>
36 #include <sys/callout.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
41 #include <dev/acpi/acpivar.h>
43 #include <machine/pio.h>
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wskbdvar.h>
46 #include <dev/isa/isareg.h>
49 #define DPRINTF(x) do { printf x; } while (/* CONSTCOND */0)
56 struct acpi_devnode
*sc_node
;
60 #define HP_PSW_DISPLAY_CYCLE 0
61 #define HP_PSW_BRIGHTNESS_UP 1
62 #define HP_PSW_BRIGHTNESS_DOWN 2
63 #define HP_PSW_SLEEP 3
65 struct sysmon_pswitch sc_smpsw
[HP_PSW_LAST
];
66 bool sc_smpsw_displaycycle_valid
;
67 bool sc_smpsw_sleep_valid
;
70 #define HP_QLB_Quick 0x88
71 #define HP_QLB_DVD 0x8e
72 #define HP_QLB_FullBackward 0x90
73 #define HP_QLB_Play 0xa2
74 #define HP_QLB_FullForward 0x99
75 #define HP_QLB_Stop 0xa4
76 #define HP_QLB_VolumeMute 0xa0
77 #define HP_QLB_VolumeDown 0xae
78 #define HP_QLB_VolumeUp 0xb0
80 #define HP_QLB_Help 0xb1
81 #define HP_QLB_WWW 0xb2
82 #define HP_QLB_DisplayCycle /* ??? */
83 #define HP_QLB_Sleep 0xdf
84 #define HP_QLB_Lock 0x8a
85 #define HP_QLB_BrightnessDown /* ??? */
86 #define HP_QLB_BrightnessUp /* ??? */
87 #define HP_QLB_ChasisOpen 0xe3
89 static int hpqlb_match(device_t
, cfdata_t
, void *);
90 static void hpqlb_attach(device_t
, device_t
, void *);
92 static int hpqlb_finalize(device_t
);
93 static int hpqlb_hotkey_handler(struct wskbd_softc
*, void *, u_int
, int);
95 static void hpqlb_init(device_t
);
96 static bool hpqlb_resume(device_t
, pmf_qual_t
);
98 CFATTACH_DECL_NEW(hpqlb
, sizeof(struct hpqlb_softc
),
99 hpqlb_match
, hpqlb_attach
, NULL
, NULL
);
101 static const char * const hpqlb_ids
[] = {
108 hpqlb_match(device_t parent
, cfdata_t match
, void *opaque
)
110 struct acpi_attach_args
*aa
= opaque
;
112 if (aa
->aa_node
->ad_type
!= ACPI_TYPE_DEVICE
)
115 return acpi_match_hid(aa
->aa_node
->ad_devinfo
, hpqlb_ids
);
119 hpqlb_attach(device_t parent
, device_t self
, void *opaque
)
121 struct hpqlb_softc
*sc
= device_private(self
);
122 struct acpi_attach_args
*aa
= opaque
;
124 sc
->sc_node
= aa
->aa_node
;
128 aprint_normal(": HP Quick Launch Buttons\n");
132 if (config_finalize_register(self
, hpqlb_finalize
) != 0)
133 aprint_error_dev(self
,
134 "WARNING: unable to register hpqlb finalizer\n");
136 sc
->sc_smpsw_displaycycle_valid
= true;
137 sc
->sc_smpsw
[HP_PSW_DISPLAY_CYCLE
].smpsw_name
=
138 PSWITCH_HK_DISPLAY_CYCLE
;
139 sc
->sc_smpsw
[HP_PSW_DISPLAY_CYCLE
].smpsw_type
=
141 if (sysmon_pswitch_register(&sc
->sc_smpsw
[HP_PSW_DISPLAY_CYCLE
])) {
142 aprint_error_dev(self
, "couldn't register with sysmon\n");
143 sc
->sc_smpsw_displaycycle_valid
= false;
146 sc
->sc_smpsw_sleep_valid
= true;
147 sc
->sc_smpsw
[HP_PSW_SLEEP
].smpsw_name
= device_xname(self
);
148 sc
->sc_smpsw
[HP_PSW_SLEEP
].smpsw_type
= PSWITCH_TYPE_SLEEP
;
149 if (sysmon_pswitch_register(&sc
->sc_smpsw
[HP_PSW_SLEEP
])) {
150 aprint_error_dev(self
, "couldn't register sleep with sysmon\n");
151 sc
->sc_smpsw_sleep_valid
= false;
154 if (!pmf_device_register(self
, NULL
, hpqlb_resume
))
155 aprint_error_dev(self
, "couldn't establish power handler\n");
159 hpqlb_hotkey_handler(struct wskbd_softc
*wskbd_sc
, void *cookie
,
160 u_int type
, int value
)
162 struct hpqlb_softc
*sc
= cookie
;
166 case HP_QLB_VolumeMute
:
167 if (type
!= WSCONS_EVENT_KEY_DOWN
)
169 pmf_event_inject(NULL
, PMFE_AUDIO_VOLUME_TOGGLE
);
171 case HP_QLB_VolumeDown
:
172 if (type
!= WSCONS_EVENT_KEY_DOWN
)
174 pmf_event_inject(NULL
, PMFE_AUDIO_VOLUME_DOWN
);
176 case HP_QLB_VolumeUp
:
177 if (type
!= WSCONS_EVENT_KEY_DOWN
)
179 pmf_event_inject(NULL
, PMFE_AUDIO_VOLUME_UP
);
183 case HP_QLB_DisplayCycle
: /* ??? */
184 if (type
!= WSCONS_EVENT_KEY_DOWN
)
186 if (sc
->sc_smpsw_displaycycle_valid
== false)
188 sysmon_pswitch_event(&sc
->sc_smpsw
[HP_PSW_DISPLAY_CYCLE
],
189 PSWITCH_EVENT_PRESSED
);
193 if (type
!= WSCONS_EVENT_KEY_DOWN
)
195 if (sc
->sc_smpsw_sleep_valid
== false) {
196 DPRINTF(("%s: Sleep hotkey\n",
197 device_xname(sc
->sc_dev
)));
200 sysmon_pswitch_event(&sc
->sc_smpsw
[HP_PSW_SLEEP
],
201 PSWITCH_EVENT_PRESSED
);
204 case HP_QLB_BrightnessDown
: /* ??? */
205 if (type
!= WSCONS_EVENT_KEY_DOWN
)
207 pmf_event_inject(NULL
, PMFE_DISPLAY_BRIGHTNESS_DOWN
);
209 case HP_QLB_BrightnessUp
: /* ??? */
210 if (type
!= WSCONS_EVENT_KEY_DOWN
)
212 pmf_event_inject(NULL
, PMFE_DISPLAY_BRIGHTNESS_UP
);
215 case HP_QLB_ChasisOpen
:
216 if (type
!= WSCONS_EVENT_KEY_DOWN
)
218 pmf_event_inject(NULL
, PMFE_CHASSIS_LID_OPEN
);
221 DPRINTF(("%s: unknown hotkey 0x%02x\n",
222 device_xname(sc
->sc_dev
), value
));
223 ret
= 0; /* Assume, this is no hotkey */
231 hpqlb_init(device_t self
)
234 /* HPQ0006: HP Quick Launch Buttons */
235 /* HPQ0007: HP Remote Device */
236 /* val 0, 1 or 7 == HPQ0006 */
237 /* val not 0, 1 or 7 == HPQ0007 */
239 /* Turn on Quick Launch Buttons */
240 outb(IO_RTC
+2, 0xaf);
241 outb(IO_RTC
+3, 7 /* val */);
245 hpqlb_finalize(device_t self
)
249 struct hpqlb_softc
*sc
= device_private(self
);
250 static int done_once
= 0;
252 /* Since we only handle real hardware, we only need to be
259 for (dv
= deviter_first(&di
, DEVITER_F_ROOT_FIRST
); dv
!= NULL
;
260 dv
= deviter_next(&di
)) {
261 if (!device_is_a(dv
, "wskbd"))
264 /* Make sure, we don't get a wskbd from a USB keyboard.
265 * QLB only works on the wskbd attached on pckbd. */
266 if (!device_is_a(device_parent(dv
), "pckbd"))
269 aprint_normal_dev(self
, "registering on %s\n",
273 deviter_release(&di
);
276 aprint_error_dev(self
, "WARNING: no matching wskbd found\n");
280 sc
->sc_wskbddev
= dv
;
282 wskbd_hotkey_register(sc
->sc_wskbddev
, sc
, hpqlb_hotkey_handler
);
288 hpqlb_resume(device_t self
, pmf_qual_t qual
)