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]
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Usage: kbd [-r] [-t] [-l] [-c on|off] [-a enable|disable|alternate]
28 * [-d keyboard device] [-D autorepeat dealy] [-R autorepeat
30 * kbd [-i] [-d keyboard device]
32 * kbd -b [keyboard|console] frequency
33 * -r reset the keyboard as if power-up
34 * -t return the type of the keyboard being used
35 * -l return the layout of the keyboard being used,
36 * and the Autorepeat settings
37 * -i read in the default configuration file
38 * -c on|off turn on|off clicking
39 * -a enable|disable|alternate sets abort sequence
40 * -D autorepeat delay sets autorepeat dealy, unit in ms
41 * -R autorepeat rate sets autorepeat rate, unit in ms
42 * -d keyboard device chooses the kbd device, default /dev/kbd.
43 * -s keyboard layout sets keyboard layout
44 * -b [keyboard| console] frequency
45 * sets keyboard or console beeper frequency
48 #include <sys/types.h>
49 #include <sys/ioctl.h>
65 #define KBD_DEVICE "/dev/kbd" /* default keyboard device */
67 #define KBD_LAYOUT_FILE "/usr/share/lib/keytables/type_6/kbd_layouts"
68 #define MAX_LAYOUT_NUM 128
69 #define MAX_LINE_SIZE 256
70 #define DEFAULT_KBD_LAYOUT 33
72 #define KBD_FMRI "svc:/system/keymap:default"
73 #define KBD_PG "keymap"
74 #define KBD_PROP_LAYOUT "layout"
75 #define KBD_PROP_KEYCLICK "keyclick"
76 #define KBD_PROP_KEYBOARD_ABORT "keyboard_abort"
77 #define KBD_PROP_RPTDELAY "repeat_delay"
78 #define KBD_PROP_RPTRATE "repeat_rate"
79 #define KBD_PROP_FREQ "kbd_beeper_freq"
80 #define KBD_PROP_CONSFREQ "console_beeper_freq"
81 #define KBD_MAX_NAME_LEN 1024
83 char *layout_names
[MAX_LAYOUT_NUM
];
84 int layout_numbers
[MAX_LAYOUT_NUM
];
85 static int layout_count
;
86 static int default_layout_number
= 0;
88 static void reset(int);
89 static int get_type(int);
90 static void get_layout(int);
91 static void kbd_defaults(int);
92 static void usage(void);
94 static int click(char *, int);
95 static int abort_enable(char *, int);
96 static int set_repeat_delay(char *, int);
97 static int set_rptdelay(int, int);
98 static int set_repeat_rate(char *, int);
99 static int set_rptrate(int, int);
101 static int get_layout_number(char *);
102 static int set_layout(int, int);
103 static int get_layouts(void);
104 static int set_kbd_layout(int, char *);
105 static int set_beep_freq(int, char *, int);
108 main(int argc
, char **argv
)
111 int rflag
, tflag
, lflag
, cflag
, dflag
, aflag
, iflag
, errflag
,
112 Dflag
, Rflag
, rtlacDRflag
, sflag
, bflag
;
113 char *copt
, *aopt
, *delay
, *rate
, *layout_name
, *b_type
, *freq_str
;
114 char *kbdname
= KBD_DEVICE
, *endptr
= NULL
;
119 rflag
= tflag
= cflag
= dflag
= aflag
= iflag
= errflag
= lflag
=
120 Dflag
= Rflag
= sflag
= bflag
= 0;
121 copt
= aopt
= (char *)0;
123 (void) setlocale(LC_ALL
, "");
124 #if !defined(TEXT_DOMAIN)
125 #define TEXT_DOMAIN "SYS_TEST"
127 (void) textdomain(TEXT_DOMAIN
);
129 while ((c
= getopt(argc
, argv
, "rtlisc:a:d:D:R:b:")) != EOF
) {
176 * Check for valid arguments:
178 * If argument parsing failed or if there are left-over
179 * command line arguments(except -s and -b option),
180 * then we're done now.
182 if (errflag
!= 0 || (sflag
== 0 && bflag
== 0 && argc
!= optind
)) {
188 * kbd requires that the user specify either "-i" or "-s" or "-b" or
189 * at least one of -[rtlacDR]. The "-d" option is, well, optional.
190 * We don't care if it's there or not.
192 rtlacDRflag
= rflag
+ tflag
+ lflag
+ aflag
+ cflag
+ Dflag
+ Rflag
;
193 if (!((iflag
!= 0 && sflag
== 0 && bflag
== 0 && rtlacDRflag
== 0) ||
194 (iflag
== 0 && sflag
!= 0 && bflag
== 0 && dflag
== 0 &&
196 (iflag
== 0 && sflag
== 0 && bflag
== 0 && rtlacDRflag
!= 0) ||
197 (iflag
== 0 && sflag
== 0 && bflag
!= 0 && rtlacDRflag
== 0))) {
202 if (Dflag
&& atoi(delay
) <= 0) {
203 (void) fprintf(stderr
, "Invalid arguments: -D %s\n", delay
);
208 if (Rflag
&& atoi(rate
) <= 0) {
209 (void) fprintf(stderr
, "Invalid arguments: -R %s\n", rate
);
215 * Open the keyboard device
217 if ((kbd
= open(kbdname
, O_RDWR
)) < 0) {
218 perror("opening the keyboard");
219 (void) fprintf(stderr
, "kbd: Cannot open %s\n", kbdname
);
225 exit(0); /* A mutually exclusive option */
230 (void) get_type(kbd
);
235 if (cflag
&& (error
= click(copt
, kbd
)) != 0)
241 if (aflag
&& (error
= abort_enable(aopt
, kbd
)) != 0)
244 if (Dflag
&& (error
= set_repeat_delay(delay
, kbd
)) != 0)
247 if (Rflag
&& (error
= set_repeat_rate(rate
, kbd
)) != 0)
251 if (argc
== optind
) {
253 } else if (argc
== (optind
+ 1)) {
254 layout_name
= argv
[optind
];
260 if ((error
= set_kbd_layout(kbd
, layout_name
)) != 0)
265 if (argc
== optind
) {
267 } else if (argc
== (optind
+ 1)) {
268 b_type
= argv
[argc
- 2];
274 if (strcmp(b_type
, "keyboard") && strcmp(b_type
, "console")) {
279 freq_str
= argv
[argc
- 1];
281 freq_val
= (int)strtol(freq_str
, &endptr
, 10);
282 if (errno
!= 0 || endptr
[0] != '\0') {
287 if (freq_val
< 0 || freq_val
> INT16_MAX
) {
288 (void) fprintf(stderr
, "Invalid arguments: -b %s\n",
290 (void) fprintf(stderr
, "Frequency range: [0 - %d]\n",
295 if ((error
= set_beep_freq(kbd
, b_type
, freq_val
)) != 0)
303 * this routine gets the type of the keyboard being used
306 set_kbd_layout(int kbd
, char *layout_name
)
311 /* layout setting is possible only for USB type keyboards */
312 if (get_type(kbd
) != KB_USB
) {
313 (void) fprintf(stderr
, "The -s option does not apply for this"
315 "Only USB/PS2 type keyboards support this option.\n");
319 /* get the language info from the layouts file */
320 if (get_layouts() != 0)
323 if (layout_name
!= NULL
) {
324 if ((layout_num
= get_layout_number(layout_name
)) == -1) {
325 (void) fprintf(stderr
, "%s: unknown layout name\n"
326 "Please refer to 'kbd -s' to get the "
327 "supported layouts.\n", layout_name
);
331 int i
, j
, print_cnt
, input_num
;
332 boolean_t input_right
= B_TRUE
;
333 boolean_t default_input
= B_FALSE
;
334 char input
[8]; /* 8 chars is enough for numbers */
336 print_cnt
= (layout_count
% 2) ?
337 layout_count
/2+1 : layout_count
/2;
339 for (i
= 1; i
<= print_cnt
; i
++) {
340 (void) printf("%2d. %-30s", i
,
343 if (j
<= layout_count
) {
344 (void) printf("%-2d. %-30s\n", j
,
348 (void) printf(gettext("\nTo select the keyboard layout,"
349 " enter a number [default %d]:"),
350 default_layout_number
+1);
353 if (input_right
== B_FALSE
)
354 (void) printf(gettext("Invalid input. "
355 "Please input a number "
357 (void) memset(input
, 0, 8);
358 (void) fflush(stdin
);
359 (void) fgets(input
, 8, stdin
);
360 if (strlen(input
) > 4) {
361 input_right
= B_FALSE
;
364 if (input
[0] == '\n') {
365 default_input
= B_TRUE
;
368 input_right
= B_TRUE
;
369 /* check if the inputs are numbers 0~9 */
370 for (i
= 0; i
< (strlen(input
) - 1); i
++) {
371 if ((input
[i
] < '0') ||
373 input_right
= B_FALSE
;
377 if (input_right
== B_FALSE
)
379 input_num
= atoi(input
);
380 if ((input_num
> 0) &&
381 (input_num
<= layout_count
))
384 input_right
= B_FALSE
;
386 if (default_input
== B_TRUE
)
387 layout_num
= DEFAULT_KBD_LAYOUT
;
389 layout_num
= layout_numbers
[--input_num
];
392 if ((error
= set_layout(kbd
, layout_num
)) != 0)
399 * This routine sets keyboard or console beeper frequency
402 set_beep_freq(int fd
, char *type
, int freq
)
404 struct freq_request fr_struct
;
406 if (strcmp(type
, "keyboard") == 0)
407 fr_struct
.type
= KBD_BEEP
;
408 else if (strcmp(type
, "console") == 0)
409 fr_struct
.type
= CONSOLE_BEEP
;
413 fr_struct
.freq
= (int16_t)freq
;
415 return (ioctl(fd
, KIOCSETFREQ
, &fr_struct
));
419 * this routine resets the state of the keyboard as if power-up
428 if (ioctl(kbd
, KIOCCMD
, &cmd
)) {
429 perror("kbd: ioctl error");
436 * this routine gets the type of the keyboard being used
443 if (ioctl(kbd
, KIOCTYPE
, &kbd_type
)) {
444 perror("ioctl (kbd type)");
451 (void) printf("Type 3 Sun keyboard\n");
455 (void) printf("Type 4 Sun keyboard\n");
459 (void) printf("ASCII\n");
463 (void) printf("PC\n");
467 (void) printf("USB keyboard\n");
471 (void) printf("Unknown keyboard type\n");
478 * this routine gets the layout of the keyboard being used
479 * also, included the autorepeat delay and rate being used
486 /* these two variables are used for getting delay&rate */
490 if (ioctl(kbd
, KIOCTYPE
, &kbd_type
)) {
491 perror("ioctl (kbd type)");
495 if (ioctl(kbd
, KIOCLAYOUT
, &kbd_layout
)) {
496 perror("ioctl (kbd layout)");
500 (void) printf("type=%d\nlayout=%d (0x%.2x)\n",
501 kbd_type
, kbd_layout
, kbd_layout
);
503 /* below code is used to get the autorepeat delay and rate */
504 if (ioctl(kbd
, KIOCGRPTDELAY
, &delay
)) {
505 perror("ioctl (kbd get repeat delay)");
509 if (ioctl(kbd
, KIOCGRPTRATE
, &rate
)) {
510 perror("ioctl (kbd get repeat rate)");
514 (void) printf("delay(ms)=%d\n", delay
);
515 (void) printf("rate(ms)=%d\n", rate
);
519 * this routine enables or disables clicking of the keyboard
522 click(char *copt
, int kbd
)
526 if (strcmp(copt
, "on") == 0)
528 else if (strcmp(copt
, "off") == 0)
529 cmd
= KBD_CMD_NOCLICK
;
531 (void) fprintf(stderr
, "wrong option -- %s\n", copt
);
536 if (ioctl(kbd
, KIOCCMD
, &cmd
)) {
537 perror("kbd ioctl (keyclick)");
544 * this routine enables/disables/sets BRK or abort sequence feature
547 abort_enable(char *aopt
, int kbd
)
551 if (strcmp(aopt
, "alternate") == 0)
552 enable
= KIOCABORTALTERNATE
;
553 else if (strcmp(aopt
, "enable") == 0)
554 enable
= KIOCABORTENABLE
;
555 else if (strcmp(aopt
, "disable") == 0)
556 enable
= KIOCABORTDISABLE
;
558 (void) fprintf(stderr
, "wrong option -- %s\n", aopt
);
563 if (ioctl(kbd
, KIOCSKABORTEN
, &enable
)) {
564 perror("kbd ioctl (abort enable)");
571 set_rptdelay(int delay
, int kbd
)
574 * The error message depends on the different inputs.
575 * a. the input is a invalid integer(unit in ms)
576 * b. the input is a integer less than the minimal delay setting.
577 * The condition (a) has been covered by main function and kbd_defaults
580 if (ioctl(kbd
, KIOCSRPTDELAY
, &delay
) == -1) {
581 if (delay
< KIOCRPTDELAY_MIN
)
582 (void) fprintf(stderr
, "kbd: specified delay %d is "
583 "less than minimum %d\n", delay
, KIOCRPTDELAY_MIN
);
585 perror("kbd: set repeat delay");
593 * this routine set autorepeat delay
596 set_repeat_delay(char *delay_str
, int kbd
)
598 int delay
= atoi(delay_str
);
600 return (set_rptdelay(delay
, kbd
));
604 set_rptrate(int rate
, int kbd
)
607 * The input validation check has been covered by main function
608 * and kbd_defaults function.Here just give an error message if
611 if (ioctl(kbd
, KIOCSRPTRATE
, &rate
) == -1) {
612 perror("kbd: set repeat rate");
619 * this routine set autorepeat rate
622 set_repeat_rate(char *rate_str
, int kbd
)
624 int rate
= atoi(rate_str
);
626 return (set_rptrate(rate
, kbd
));
629 #define BAD_DEFAULT_STR "kbd: bad default value for %s: %s\n"
630 #define BAD_DEFAULT_INT "kbd: bad default value for %s: %d\n"
631 #define BAD_DEFAULT_LLINT "kbd: bad default value for %s: %lld\n"
634 kbd_defaults(int kbd
)
636 scf_handle_t
*h
= NULL
;
637 scf_snapshot_t
*snap
= NULL
;
638 scf_instance_t
*inst
= NULL
;
639 scf_propertygroup_t
*pg
= NULL
;
640 scf_property_t
*prop
= NULL
;
641 scf_value_t
*val
= NULL
;
644 char *val_layout
= NULL
, *val_abort
= NULL
;
646 int64_t val_delay
, val_rate
;
647 int64_t val_kbd_beeper
, val_console_beeper
;
649 if ((h
= scf_handle_create(SCF_VERSION
)) == NULL
||
650 scf_handle_bind(h
) != 0 ||
651 (inst
= scf_instance_create(h
)) == NULL
||
652 (snap
= scf_snapshot_create(h
)) == NULL
||
653 (pg
= scf_pg_create(h
)) == NULL
||
654 (prop
= scf_property_create(h
)) == NULL
||
655 (val
= scf_value_create(h
)) == NULL
) {
659 if (scf_handle_decode_fmri(h
, KBD_FMRI
, NULL
, NULL
, inst
,
660 NULL
, NULL
, SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0) {
664 if (scf_instance_get_snapshot(inst
, "running", snap
) != 0) {
665 scf_snapshot_destroy(snap
);
669 if (scf_instance_get_pg_composed(inst
, snap
, KBD_PG
, pg
) != 0) {
673 if ((val_abort
= malloc(KBD_MAX_NAME_LEN
)) == NULL
) {
674 (void) fprintf(stderr
,
675 "Can not alloc memory for keyboard properties\n");
679 if ((val_layout
= malloc(KBD_MAX_NAME_LEN
)) == NULL
) {
680 (void) fprintf(stderr
,
681 "Can not alloc memory for keyboard properties\n");
685 if (scf_pg_get_property(pg
, KBD_PROP_KEYCLICK
, prop
) != 0 ||
686 scf_property_get_value(prop
, val
) != 0 ||
687 scf_value_get_boolean(val
, &val_click
) == -1) {
688 (void) fprintf(stderr
, "Can not get KEYCLICK\n");
692 (void) click("on", kbd
);
693 else if (val_click
== 0)
694 (void) click("off", kbd
);
696 (void) fprintf(stderr
,
697 BAD_DEFAULT_INT
, KBD_PROP_KEYCLICK
, val_click
);
699 if (scf_pg_get_property(pg
, KBD_PROP_KEYBOARD_ABORT
, prop
) != 0 ||
700 scf_property_get_value(prop
, val
) != 0 ||
701 scf_value_get_astring(val
, val_abort
, KBD_MAX_NAME_LEN
) == -1) {
702 (void) fprintf(stderr
, "Can not get KEYBOARD_ABORT\n");
705 if (*val_abort
!= '\0') {
707 * ABORT must equal "enable", "disable" or "alternate"
709 if ((strcmp(val_abort
, "enable") == 0) ||
710 (strcmp(val_abort
, "alternate") == 0) ||
711 (strcmp(val_abort
, "disable") == 0))
712 (void) abort_enable(val_abort
, kbd
);
714 (void) fprintf(stderr
, BAD_DEFAULT_STR
,
715 KBD_PROP_KEYBOARD_ABORT
, val_abort
);
718 if (scf_pg_get_property(pg
, KBD_PROP_RPTDELAY
, prop
) != 0 ||
719 scf_property_get_value(prop
, val
) != 0 ||
720 scf_value_get_integer(val
, &val_delay
) == -1) {
721 (void) fprintf(stderr
, "Can not get RPTDELAY\n");
725 (void) set_rptdelay(val_delay
, kbd
);
727 (void) fprintf(stderr
,
728 BAD_DEFAULT_LLINT
, KBD_PROP_RPTDELAY
, val_delay
);
730 if (scf_pg_get_property(pg
, KBD_PROP_RPTRATE
, prop
) != 0 ||
731 scf_property_get_value(prop
, val
) != 0 ||
732 scf_value_get_integer(val
, &val_rate
) == -1) {
733 (void) fprintf(stderr
, "Can not get RPTRATE\n");
737 (void) set_rptrate(val_rate
, kbd
);
739 (void) fprintf(stderr
,
740 BAD_DEFAULT_LLINT
, KBD_PROP_RPTRATE
, val_rate
);
742 if (scf_pg_get_property(pg
, KBD_PROP_LAYOUT
, prop
) != 0 ||
743 scf_property_get_value(prop
, val
) != 0 ||
744 scf_value_get_astring(val
, val_layout
, KBD_MAX_NAME_LEN
) == -1) {
745 (void) fprintf(stderr
, "Can not get LAYOUT\n");
748 if (*val_layout
!= '\0') {
750 * LAYOUT must be one of the layouts supported in kbd_layouts
752 if (get_layouts() != 0)
755 if ((layout_num
= get_layout_number(val_layout
)) == -1) {
756 (void) fprintf(stderr
,
757 BAD_DEFAULT_STR
, KBD_PROP_LAYOUT
, val_layout
);
761 (void) set_layout(kbd
, layout_num
);
764 if (scf_pg_get_property(pg
, KBD_PROP_FREQ
, prop
) != 0 ||
765 scf_property_get_value(prop
, val
) != 0 ||
766 scf_value_get_integer(val
, &val_kbd_beeper
) == -1) {
767 (void) fprintf(stderr
, "Can not get FREQ\n");
770 if (val_kbd_beeper
>= 0 && val_kbd_beeper
<= INT16_MAX
)
771 (void) set_beep_freq(kbd
, "keyboard", val_kbd_beeper
);
773 (void) fprintf(stderr
,
774 BAD_DEFAULT_LLINT
, KBD_PROP_FREQ
, val_kbd_beeper
);
776 if (scf_pg_get_property(pg
, KBD_PROP_CONSFREQ
, prop
) != 0 ||
777 scf_property_get_value(prop
, val
) != 0 ||
778 scf_value_get_integer(val
, &val_console_beeper
) == -1) {
779 (void) fprintf(stderr
, "Can not get CONSFREQ\n");
782 if (val_console_beeper
>= 0 && val_console_beeper
<= INT16_MAX
)
783 (void) set_beep_freq(kbd
, "console", val_console_beeper
);
785 (void) fprintf(stderr
,
786 BAD_DEFAULT_LLINT
, KBD_PROP_CONSFREQ
, val_console_beeper
);
792 scf_snapshot_destroy(snap
);
793 scf_value_destroy(val
);
794 scf_property_destroy(prop
);
796 scf_instance_destroy(inst
);
797 scf_handle_destroy(h
);
801 get_layout_number(char *layout
)
804 int layout_number
= -1;
806 for (i
= 0; i
< layout_count
; i
++) {
807 if (strcmp(layout
, layout_names
[i
]) == 0) {
808 layout_number
= layout_numbers
[i
];
813 return (layout_number
);
820 char buffer
[MAX_LINE_SIZE
];
825 if ((stream
= fopen(KBD_LAYOUT_FILE
, "r")) == 0) {
826 perror(KBD_LAYOUT_FILE
);
830 while ((fgets(buffer
, MAX_LINE_SIZE
, stream
) != NULL
) &&
831 (i
< MAX_LAYOUT_NUM
)) {
832 if (buffer
[0] == '#')
834 if ((result
= strtok(buffer
, "=")) == NULL
)
836 if ((tmpbuf
= strdup(result
)) != NULL
) {
837 layout_names
[i
] = tmpbuf
;
839 perror("out of memory getting layout names");
842 if ((result
= strtok(NULL
, "\n")) == NULL
)
844 layout_numbers
[i
] = atoi(result
);
845 if (strcmp(tmpbuf
, "US-English") == 0)
846 default_layout_number
= i
;
855 * this routine sets the layout of the keyboard being used
858 set_layout(int kbd
, int layout_num
)
861 if (ioctl(kbd
, KIOCSLAYOUT
, layout_num
)) {
862 perror("ioctl (set kbd layout)");
869 static char *usage1
= "kbd [-r] [-t] [-l] [-a enable|disable|alternate]";
870 static char *usage2
= " [-c on|off][-D delay][-R rate][-d keyboard device]";
871 static char *usage3
= "kbd -i [-d keyboard device]";
872 static char *usage4
= "kbd -s [language]";
873 static char *usage5
= "kbd -b [keyboard|console] frequency";
878 (void) fprintf(stderr
, "Usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", usage1
,
879 usage2
, usage3
, usage4
, usage5
);