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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2015 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
29 * Solaris x86 Generic ACPI Video Extensions Hotkey driver
31 #include <sys/hotkey_drv.h>
32 #include <sys/smbios.h>
35 * Vendor specific hotkey support list
36 * 1. Toshiba: acpi_toshiba
38 struct vendor_hotkey_drv vendor_hotkey_drv_list
[] = {
39 /* vendor, module name, enable? */
40 {"Toshiba", "acpi_toshiba", B_TRUE
},
45 enum vga_output_type
{
53 struct acpi_video_output
{
54 struct acpi_drv_dev dev
;
56 enum vga_output_type type
;
57 struct acpi_video_output
*next
;
60 struct acpi_video_brightness
{
61 struct acpi_drv_dev dev
;
66 uint32_t cur_level_index
;
67 uint32_t output_index
;
68 struct acpi_video_brightness
*next
;
71 struct acpi_video_switch
{
72 struct acpi_drv_dev dev
;
73 struct acpi_video_switch
*next
;
76 /* ACPI video extension hotkey for video switch and brightness control */
77 static struct acpi_video
{
78 struct acpi_video_output
*vid_outputs
;
79 uint32_t total_outputs
;
80 struct acpi_video_brightness
*vid_brightness
;
81 uint32_t total_brightness
;
82 struct acpi_video_switch
*vid_switch
;
83 uint32_t total_switch
;
86 int hotkey_drv_debug
= 0;
88 static struct acpi_video_smbios_info
{
91 } acpi_brightness_get_blacklist
[] = {
92 { /* Dell AdamoXPS laptop */
96 { /* termination entry */
102 * -1 = check acpi_brightness_get_blacklist[].
103 * 0 = enable brightness get.
104 * 1 = disable brightness get.
106 int acpi_brightness_get_disable
= -1;
109 #define ACPI_METHOD_DOS "_DOS"
110 #define ACPI_METHOD_DOD "_DOD"
112 #define ACPI_DEVNAME_CRT "CRT"
113 #define ACPI_DEVNAME_LCD "LCD"
114 #define ACPI_DEVNAME_TV "TV"
115 #define ACPI_METHOD_ADR "_ADR"
116 #define ACPI_METHOD_DDC "_DDC"
117 #define ACPI_METHOD_DCS "_DCS"
118 #define ACPI_METHOD_DGS "_DGS"
119 #define ACPI_METHOD_DSS "_DSS"
121 #define VIDEO_NOTIFY_SWITCH 0x80
122 #define VIDEO_NOTIFY_SWITCH_STATUS 0x81
123 #define VIDEO_NOTIFY_SWITCH_CYCLE 0x82
124 #define VIDEO_NOTIFY_SWITCH_NEXT 0x83
125 #define VIDEO_NOTIFY_SWITCH_PREV 0x84
127 #define VIDEO_NOTIFY_BRIGHTNESS_CYCLE 0x85
128 #define VIDEO_NOTIFY_BRIGHTNESS_INC 0x86
129 #define VIDEO_NOTIFY_BRIGHTNESS_DEC 0x87
130 #define VIDEO_NOTIFY_BRIGHTNESS_ZERO 0x88
132 /* Output device status */
133 #define ACPI_DRV_DCS_CONNECTOR_EXIST (1 << 0)
134 #define ACPI_DRV_DCS_ACTIVE (1 << 1)
135 #define ACPI_DRV_DCS_READY (1 << 2)
136 #define ACPI_DRV_DCS_FUNCTIONAL (1 << 3)
137 #define ACPI_DRV_DCS_ATTACHED (1 << 4)
139 /* _DOS default value is 1 */
141 #define VIDEO_POLICY_SWITCH_OS 0x0
142 #define VIDEO_POLICY_SWITCH_BIOS 0x1
143 #define VIDEO_POLICY_SWITCH_LOCKED 0x2
144 #define VIDEO_POLICY_SWITCH_OS_EVENT 0x3
147 #define VIDEO_POLICY_BRIGHTNESS_OS 0x4
148 #define VIDEO_POLICY_BRIGHTNESS_BIOS 0x0
150 /* Set _DOS for video control policy */
152 acpi_video_set_dos(struct acpi_video
*vidp
, uint32_t policy
)
154 struct acpi_video_switch
*vidsp
;
157 ACPI_OBJECT_LIST objlist
;
159 obj
.Type
= ACPI_TYPE_INTEGER
;
160 obj
.Integer
.Value
= policy
;
162 objlist
.Pointer
= &obj
;
164 vidsp
= vidp
->vid_switch
;
165 while (vidsp
!= NULL
) {
166 status
= AcpiEvaluateObject(vidsp
->dev
.hdl
, ACPI_METHOD_DOS
,
168 if (ACPI_FAILURE(status
))
169 cmn_err(CE_WARN
, "!acpi_video_set_dos failed.");
175 * Get the current brightness level and index.
178 acpi_video_brightness_get(struct acpi_video_brightness
*vidbp
)
182 if (acpi_brightness_get_disable
) {
183 /* simply initialize current brightness to the highest level */
184 vidbp
->cur_level_index
= vidbp
->nlevel
- 1;
185 vidbp
->cur_level
= vidbp
->levels
[vidbp
->cur_level_index
];
186 return (ACPI_DRV_OK
);
189 if (acpica_eval_int(vidbp
->dev
.hdl
, "_BQC", &vidbp
->cur_level
)
191 vidbp
->cur_level
= 0;
192 return (ACPI_DRV_ERR
);
195 for (i
= 0; i
< vidbp
->nlevel
; i
++) {
196 if (vidbp
->levels
[i
] == vidbp
->cur_level
) {
197 vidbp
->cur_level_index
= i
;
198 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
199 cmn_err(CE_NOTE
, "!acpi_video_brightness_get():"
200 " cur_level = %d, cur_level_index = %d\n",
201 vidbp
->cur_level
, i
);
207 return (ACPI_DRV_OK
);
211 acpi_video_brightness_set(struct acpi_video_brightness
*vidbp
, uint32_t level
)
213 if (acpi_drv_set_int(vidbp
->dev
.hdl
, "_BCM", vidbp
->levels
[level
])
215 return (ACPI_DRV_ERR
);
218 vidbp
->cur_level
= vidbp
->levels
[level
];
219 vidbp
->cur_level_index
= level
;
221 return (ACPI_DRV_OK
);
225 hotkey_drv_gen_sysevent(dev_info_t
*dip
, char *event
)
229 /* Generate/log EC_ACPIEV sysevent */
230 err
= ddi_log_sysevent(dip
, DDI_VENDOR_SUNW
, EC_ACPIEV
,
231 event
, NULL
, NULL
, DDI_NOSLEEP
);
233 if (err
!= DDI_SUCCESS
) {
235 "!failed to log hotkey sysevent, err code %x\n", err
);
241 acpi_video_switch_notify(ACPI_HANDLE hdl
, uint32_t notify
, void *ctx
)
243 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
244 cmn_err(CE_NOTE
, "!acpi_video_switch_notify: got event 0x%x.\n",
248 mutex_enter(acpi_hotkey
.hotkey_lock
);
250 case VIDEO_NOTIFY_SWITCH
:
251 case VIDEO_NOTIFY_SWITCH_CYCLE
:
252 case VIDEO_NOTIFY_SWITCH_NEXT
:
253 case VIDEO_NOTIFY_SWITCH_PREV
:
254 hotkey_drv_gen_sysevent(acpi_hotkey
.dip
,
255 ESC_ACPIEV_DISPLAY_SWITCH
);
258 case VIDEO_NOTIFY_SWITCH_STATUS
:
262 if (hotkey_drv_debug
) {
264 "!acpi_video_switch_notify: unknown event 0x%x.\n",
268 mutex_exit(acpi_hotkey
.hotkey_lock
);
273 acpi_video_brightness_notify(ACPI_HANDLE hdl
, uint32_t notify
, void *ctx
)
275 struct acpi_video_brightness
*vidbp
= ctx
;
277 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
279 "!acpi_video_brightness_notify: got event 0x%x.\n",
283 mutex_enter(acpi_hotkey
.hotkey_lock
);
285 case VIDEO_NOTIFY_BRIGHTNESS_CYCLE
:
286 case VIDEO_NOTIFY_BRIGHTNESS_INC
:
287 if (vidbp
->cur_level_index
< vidbp
->nlevel
- 1) {
288 if (acpi_video_brightness_set(vidbp
,
289 vidbp
->cur_level_index
+ 1) != ACPI_DRV_OK
) {
293 acpi_drv_gen_sysevent(&vidbp
->dev
, ESC_PWRCTL_BRIGHTNESS_UP
, 0);
295 case VIDEO_NOTIFY_BRIGHTNESS_DEC
:
296 if (vidbp
->cur_level_index
> 0) {
297 if (acpi_video_brightness_set(vidbp
,
298 vidbp
->cur_level_index
- 1) != ACPI_DRV_OK
) {
302 acpi_drv_gen_sysevent(&vidbp
->dev
, ESC_PWRCTL_BRIGHTNESS_DOWN
,
305 case VIDEO_NOTIFY_BRIGHTNESS_ZERO
:
306 if (acpi_video_brightness_set(vidbp
, 0) != ACPI_DRV_OK
) {
309 acpi_drv_gen_sysevent(&vidbp
->dev
, ESC_PWRCTL_BRIGHTNESS_DOWN
,
314 if (hotkey_drv_debug
) {
315 cmn_err(CE_NOTE
, "!acpi_video_brightness_notify: "
316 "unknown event 0x%x.\n", notify
);
319 mutex_exit(acpi_hotkey
.hotkey_lock
);
323 acpi_video_notify_intall(struct acpi_video
*vidp
)
326 struct acpi_video_switch
*vidsp
;
327 struct acpi_video_brightness
*vidbp
;
330 /* bind video switch notify */
331 vidsp
= vidp
->vid_switch
;
332 for (i
= 0; i
< vidp
->total_switch
&& vidsp
!= NULL
; i
++) {
333 status
= AcpiInstallNotifyHandler(vidsp
->dev
.hdl
,
334 ACPI_DEVICE_NOTIFY
, acpi_video_switch_notify
, vidsp
);
335 if (ACPI_FAILURE(status
)) {
337 "!vids handler install failed = %d, vids = %p.",
338 status
, (void *) vidsp
);
343 /* bind brightness control notify */
344 vidbp
= vidp
->vid_brightness
;
345 for (i
= 0; i
< vidp
->total_brightness
&& vidbp
!= NULL
; i
++) {
346 status
= AcpiInstallNotifyHandler(vidbp
->dev
.hdl
,
347 ACPI_DEVICE_NOTIFY
, acpi_video_brightness_notify
, vidbp
);
348 if (ACPI_FAILURE(status
)) {
350 "!brightness handler install failed = %x, "
351 "brightness = %p.", status
, (void *) vidbp
);
356 return (ACPI_DRV_OK
);
360 acpi_video_notify_unintall(struct acpi_video
*vidp
)
362 struct acpi_video_switch
*vidsp
;
363 struct acpi_video_brightness
*vidbp
;
366 /* unbind video switch notify */
367 vidsp
= vidp
->vid_switch
;
368 for (i
= 0; i
< vidp
->total_switch
&& vidsp
!= NULL
; i
++) {
369 (void) AcpiRemoveNotifyHandler(vidsp
->dev
.hdl
,
370 ACPI_DEVICE_NOTIFY
, acpi_video_switch_notify
);
374 /* unbind brightness control notify */
375 vidbp
= vidp
->vid_brightness
;
376 for (i
= 0; i
< vidp
->total_brightness
&& vidbp
!= NULL
; i
++) {
377 (void) AcpiRemoveNotifyHandler(vidbp
->dev
.hdl
,
378 ACPI_DEVICE_NOTIFY
, acpi_video_brightness_notify
);
382 return (ACPI_DRV_OK
);
386 acpi_video_free(struct acpi_video
*vidp
)
388 struct acpi_video_switch
*vidsp
;
389 struct acpi_video_switch
*vidsp_next
;
390 struct acpi_video_brightness
*vidbp
;
391 struct acpi_video_brightness
*vidbp_next
;
392 struct acpi_video_output
*vidop
;
393 struct acpi_video_output
*vidop_next
;
395 /* free video switch objects */
396 vidsp
= vidp
->vid_switch
;
397 while (vidsp
!= NULL
) {
398 vidsp_next
= vidsp
->next
;
399 kmem_free(vidsp
, sizeof (struct acpi_video_switch
));
403 /* free video brightness control objects */
404 vidbp
= vidp
->vid_brightness
;
405 while (vidbp
!= NULL
) {
406 vidbp_next
= vidbp
->next
;
407 kmem_free(vidbp
, sizeof (struct acpi_video_brightness
));
411 /* free video output objects */
412 vidop
= vidp
->vid_outputs
;
413 while (vidop
!= NULL
) {
414 vidop_next
= vidop
->next
;
415 kmem_free(vidop
, sizeof (struct acpi_video_output
));
419 return (ACPI_DRV_OK
);
423 acpi_video_fini(struct acpi_video
*vidp
)
425 (void) acpi_video_notify_unintall(vidp
);
427 return (acpi_video_free(vidp
));
431 acpi_video_enum_output(ACPI_HANDLE hdl
, struct acpi_video
*vidp
)
434 struct acpi_video_brightness
*vidbp
;
435 struct acpi_video_output
*vidop
;
436 ACPI_BUFFER buf
= {ACPI_ALLOCATE_BUFFER
, NULL
};
440 if (acpica_eval_int(hdl
, "_ADR", &adr
) != AE_OK
)
441 return (ACPI_DRV_ERR
);
443 /* Allocate object */
444 vidop
= kmem_zalloc(sizeof (struct acpi_video_output
), KM_SLEEP
);
445 vidop
->dev
.hdl
= hdl
;
446 (void) acpi_drv_dev_init(&vidop
->dev
);
449 vidop
->next
= vidp
->vid_outputs
;
450 vidp
->vid_outputs
= vidop
;
452 if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl
, "_BCL",
453 NULL
, &buf
, ACPI_TYPE_PACKAGE
))) {
454 int i
, j
, k
, l
, m
, nlev
, tmp
;
456 vidbp
= kmem_zalloc(sizeof (struct acpi_video_brightness
),
458 vidbp
->dev
= vidop
->dev
;
460 vidbp
->output_index
= vidp
->total_outputs
;
464 * op->nlev will be needed to free op->levels.
466 vidbp
->nlevel
= nlev
= objp
->Package
.Count
;
467 vidbp
->levels
= kmem_zalloc(nlev
* sizeof (uint32_t), KM_SLEEP
);
470 * Get all the supported brightness levels.
472 for (i
= 0; i
< nlev
; i
++) {
473 ACPI_OBJECT
*o
= &objp
->Package
.Elements
[i
];
474 int lev
= o
->Integer
.Value
;
476 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
477 cmn_err(CE_NOTE
, "!acpi_video_enum_output() "
478 "brlev=%d i=%d nlev=%d\n", lev
, i
, nlev
);
480 if (o
->Type
!= ACPI_TYPE_INTEGER
) {
483 vidbp
->levels
[i
] = lev
;
487 * Sort the brightness levels.
489 for (j
= 0; j
< nlev
; j
++) {
490 for (k
= 0; k
< nlev
- 1; k
++) {
491 if (vidbp
->levels
[k
] > vidbp
->levels
[k
+1]) {
492 tmp
= vidbp
->levels
[k
+1];
493 vidbp
->levels
[k
+1] = vidbp
->levels
[k
];
494 vidbp
->levels
[k
] = tmp
;
500 * The first two levels could be duplicated, so remove
503 for (l
= 0; l
< nlev
- 1; l
++) {
504 if (vidbp
->levels
[l
] == vidbp
->levels
[l
+1]) {
505 for (m
= l
+ 1; m
< nlev
- 1; m
++) {
506 vidbp
->levels
[m
] = vidbp
->levels
[m
+1];
512 vidbp
->nlevel
= nlev
;
513 (void) acpi_video_brightness_get(vidbp
);
514 vidbp
->next
= vidp
->vid_brightness
;
515 vidp
->vid_brightness
= vidbp
;
516 vidp
->total_brightness
++;
521 vidp
->total_outputs
++;
523 return (ACPI_DRV_OK
);
528 acpi_video_find_and_alloc(ACPI_HANDLE hdl
, UINT32 nest
, void *ctx
,
533 ACPI_BUFFER buf
= {ACPI_ALLOCATE_BUFFER
, NULL
};
534 struct acpi_video
*vidp
;
535 struct acpi_video_switch
*vidsp
;
537 err
= AcpiGetHandle(hdl
, ACPI_METHOD_DOS
, &tmphdl
);
541 err
= AcpiGetHandle(hdl
, ACPI_METHOD_DOD
, &tmphdl
);
545 vidp
= (struct acpi_video
*)ctx
;
546 vidsp
= kmem_zalloc(sizeof (struct acpi_video_switch
), KM_SLEEP
);
547 vidsp
->dev
.hdl
= hdl
;
548 (void) acpi_drv_dev_init(&vidsp
->dev
);
549 vidsp
->next
= vidp
->vid_switch
;
550 vidp
->vid_switch
= vidsp
;
551 vidp
->total_switch
++;
554 * Enumerate the output devices.
556 while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_DEVICE
,
557 hdl
, tmphdl
, &tmphdl
))) {
558 (void) acpi_video_enum_output(tmphdl
, vidp
);
561 if (!ACPI_FAILURE(AcpiGetName(hdl
, ACPI_FULL_PATHNAME
, &buf
))) {
563 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
565 "!acpi video switch hdl = 0x%p, path = %s.",
566 hdl
, (char *)buf
.Pointer
);
568 AcpiOsFree(buf
.Pointer
);
576 hotkey_brightness_inc(hotkey_drv_t
*htkp
)
578 struct acpi_video
*vidp
;
579 struct acpi_video_brightness
*vidbp
;
581 vidp
= (struct acpi_video
*)htkp
->acpi_video
;
583 for (vidbp
= vidp
->vid_brightness
; vidbp
!= NULL
; vidbp
= vidbp
->next
) {
584 if (vidbp
->cur_level_index
< vidbp
->nlevel
- 1) {
585 if (acpi_video_brightness_set(vidbp
,
586 vidbp
->cur_level_index
+ 1) != ACPI_DRV_OK
) {
587 return (ACPI_DRV_ERR
);
591 return (ACPI_DRV_OK
);
595 hotkey_brightness_dec(hotkey_drv_t
*htkp
)
597 struct acpi_video
*vidp
;
598 struct acpi_video_brightness
*vidbp
;
600 vidp
= (struct acpi_video
*)htkp
->acpi_video
;
602 for (vidbp
= vidp
->vid_brightness
; vidbp
!= NULL
; vidbp
= vidbp
->next
) {
603 if (vidbp
->cur_level_index
> 0) {
604 if (acpi_video_brightness_set(vidbp
,
605 vidbp
->cur_level_index
- 1) != ACPI_DRV_OK
) {
606 return (ACPI_DRV_ERR
);
611 return (ACPI_DRV_OK
);
616 acpi_video_ioctl(void *p
, int cmd
, intptr_t arg
, int mode
, cred_t
*cr
,
619 struct acpi_video
*vidp
= p
;
620 struct acpi_video_brightness
*vidbp
;
626 vidbp
= vidp
->vid_brightness
;
630 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
631 cmn_err(CE_NOTE
, "!acpi_video_ioctl cmd %d\n", cmd
);
635 case ACPI_DRV_IOC_INFO
:
637 struct acpi_drv_output_info inf
;
639 inf
.adr
= vidbp
->adr
;
640 inf
.nlev
= vidbp
->nlevel
;
641 if (copyout(&inf
, (void *)arg
, sizeof (inf
))) {
647 case ACPI_DRV_IOC_LEVELS
:
648 if (copyout(vidbp
->levels
, (void *)arg
,
649 sizeof (*vidbp
->levels
) * vidbp
->nlevel
)) {
654 case ACPI_DRV_IOC_STATUS
:
657 * Need to get the current levels through ACPI first
658 * then go through array of levels to find index.
660 struct acpi_drv_output_status status
;
664 status
.num_levels
= vidbp
->nlevel
;
665 status
.cur_level
= vidbp
->cur_level
;
666 for (i
= 0; i
< vidbp
->nlevel
; i
++) {
667 if (vidbp
->levels
[i
] == vidbp
->cur_level
) {
668 status
.cur_level_index
= i
;
669 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
670 cmn_err(CE_NOTE
, "!ACPI_DRV_IOC_STATUS "
671 "cur_level_index %d\n", i
);
676 if (copyout(&status
, (void *)arg
, sizeof (status
))) {
682 case ACPI_DRV_IOC_SET_BRIGHTNESS
: {
689 if (copyin((void *)arg
, &level
, sizeof (level
))) {
693 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
695 "!acpi_video_ioctl: set BRIGHTNESS level=%d\n",
698 if (acpi_video_brightness_set(vidbp
, level
) != ACPI_DRV_OK
) {
714 acpi_drv_hotkey_ioctl(int cmd
, intptr_t arg
, int mode
, cred_t
*cr
,
717 hotkey_drv_t
*htkp
= &acpi_hotkey
;
719 switch (htkp
->hotkey_method
) {
720 case HOTKEY_METHOD_ACPI_VIDEO
:
721 return (acpi_video_ioctl(htkp
->acpi_video
, cmd
, arg
, mode
,
723 case HOTKEY_METHOD_MISC
:
724 case HOTKEY_METHOD_VENDOR
:
725 return (htkp
->vendor_ioctl(htkp
, cmd
, arg
, mode
, cr
, rval
));
726 case HOTKEY_METHOD_NONE
:
733 acpi_video_check_blacklist(void)
735 smbios_hdl_t
*smhdl
= NULL
;
737 smbios_system_t smsys
;
738 smbios_info_t sminfo
;
740 struct acpi_video_smbios_info
*pblacklist
;
742 acpi_brightness_get_disable
= 0;
743 smhdl
= smbios_open(NULL
, SMB_VERSION
, ksmbios_flags
, NULL
);
745 ((smid
= smbios_info_system(smhdl
, &smsys
)) == SMB_ERR
) ||
746 (smbios_info_common(smhdl
, smid
, &sminfo
) == SMB_ERR
)) {
750 mfg
= (char *)sminfo
.smbi_manufacturer
;
751 product
= (char *)sminfo
.smbi_product
;
752 for (pblacklist
= acpi_brightness_get_blacklist
;
753 pblacklist
->manufacturer
!= NULL
; pblacklist
++) {
754 if ((strcmp(mfg
, pblacklist
->manufacturer
) == 0) &&
755 (strcmp(product
, pblacklist
->product
) == 0)) {
756 acpi_brightness_get_disable
= 1;
765 hotkey_acpi_video_check(hotkey_drv_t
*htkp
)
767 struct acpi_video
*vidp
;
769 vidp
= &acpi_video_hotkey
;
770 bzero(vidp
, sizeof (struct acpi_video
));
771 if (acpi_brightness_get_disable
== -1)
772 acpi_video_check_blacklist();
773 /* Find ACPI Video device handle */
774 if (ACPI_FAILURE(AcpiGetDevices(NULL
, acpi_video_find_and_alloc
,
776 return (ACPI_DRV_ERR
);
779 htkp
->acpi_video
= vidp
;
780 if (htkp
->hotkey_method
== HOTKEY_METHOD_NONE
) {
781 if (acpi_video_notify_intall(vidp
) != ACPI_DRV_OK
) {
782 (void) acpi_video_fini(vidp
);
783 htkp
->acpi_video
= NULL
;
784 return (ACPI_DRV_ERR
);
787 htkp
->hotkey_method
|= HOTKEY_METHOD_ACPI_VIDEO
;
789 acpi_video_set_dos(vidp
, VIDEO_POLICY_BRIGHTNESS_OS
|
790 VIDEO_POLICY_SWITCH_OS
);
792 return (ACPI_DRV_OK
);
796 hotkey_init(hotkey_drv_t
*htkp
)
803 /* Try to find vendor specific method */
804 for (i
= 0; vendor_hotkey_drv_list
[i
].module
!= NULL
; i
++) {
805 if (!vendor_hotkey_drv_list
[i
].enable
)
808 if ((modid
= modload("drv", vendor_hotkey_drv_list
[i
].module
))
814 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
) {
815 cmn_err(CE_NOTE
, "!loaded %s specific method.\n",
816 vendor_hotkey_drv_list
[i
].vid
);
820 /* Check availability of ACPI Video Extension method */
821 if (htkp
->hotkey_method
== HOTKEY_METHOD_NONE
||
822 htkp
->check_acpi_video
) {
823 if (hotkey_acpi_video_check(htkp
) == ACPI_DRV_OK
) {
824 if (hotkey_drv_debug
& HOTKEY_DBG_NOTICE
)
825 cmn_err(CE_NOTE
, "!find ACPI video method.\n");
830 if (htkp
->modid
!= -1) {
831 modp
= mod_hold_by_id(htkp
->modid
);
832 mutex_enter(&mod_lock
);
834 modp
->mod_loadflags
|= MOD_NOAUTOUNLOAD
;
835 mutex_exit(&mod_lock
);
836 mod_release_mod(modp
);
839 /* Create minor node for hotkey device. */
840 if (ddi_create_minor_node(htkp
->dip
, "hotkey", S_IFCHR
,
841 MINOR_HOTKEY(0), DDI_PSEUDO
, 0) == DDI_FAILURE
) {
842 if (hotkey_drv_debug
& HOTKEY_DBG_WARN
)
843 cmn_err(CE_WARN
, "hotkey: minor node create failed");
847 return (ACPI_DRV_OK
);
850 if (htkp
->vendor_fini
!= NULL
)
851 htkp
->vendor_fini(htkp
);
852 if (htkp
->modid
!= -1)
853 (void) modunload(htkp
->modid
);
855 return (ACPI_DRV_ERR
);
860 hotkey_fini(hotkey_drv_t
*htkp
)
864 if (htkp
->vendor_fini
!= NULL
)
865 htkp
->vendor_fini(htkp
);
866 if (htkp
->acpi_video
!= NULL
)
867 (void) acpi_video_fini(htkp
->acpi_video
);
868 if (htkp
->modid
!= -1) {
869 modp
= mod_hold_by_id(htkp
->modid
);
870 mutex_enter(&mod_lock
);
872 modp
->mod_loadflags
&= ~MOD_NOAUTOUNLOAD
;
873 mutex_exit(&mod_lock
);
874 mod_release_mod(modp
);
875 (void) modunload(htkp
->modid
);
878 return (ACPI_DRV_OK
);