1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Usage: kbd [-r] [-t] [-l] [-c on|off] [-a enable|disable|alternate]
28 * [-d keyboard device] [-A autorepeat count]
29 * [-D autorepeat delay] [-R autorepeat rate]
30 * kbd [-i] [-d keyboard device]
31 * kbd -s [language]
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 * -A autorepeat count sets autorepeat sequence length in chars.
41 * -D autorepeat delay sets autorepeat delay, unit in ms
42 * -R autorepeat rate sets autorepeat rate, unit in ms
43 * -d keyboard device chooses the kbd device, default /dev/kbd.
44 * -s keyboard layout sets keyboard layout
45 * -b [keyboard| console] frequency
46 * sets keyboard or console beeper frequency
47 */
48
49 #include <sys/types.h>
50 #include <sys/ioctl.h>
51 #include <sys/kbio.h>
52 #include <sys/kbd.h>
53 #include <stdio.h>
54 #include <fcntl.h>
55 #include <deflt.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <stdlib.h>
59 #include <stropts.h>
60 #include <libintl.h>
61 #include <locale.h>
62 #include <errno.h>
63 #include <inttypes.h>
64 #include <libscf.h>
65 #include <limits.h>
66
67 #define KBD_DEVICE "/dev/kbd" /* default keyboard device */
68
69 #define KBD_LAYOUT_FILE "/usr/share/lib/keytables/type_6/kbd_layouts"
70 #define MAX_LAYOUT_NUM 128
71 #define MAX_LINE_SIZE 256
72 #define DEFAULT_KBD_LAYOUT 33
73
74 #define KBD_FMRI "svc:/system/keymap:default"
75 #define KBD_PG "keymap"
76 #define KBD_PROP_LAYOUT "layout"
77 #define KBD_PROP_KEYCLICK "keyclick"
78 #define KBD_PROP_KEYBOARD_ABORT "keyboard_abort"
79 #define KBD_PROP_RPTDELAY "repeat_delay"
80 #define KBD_PROP_RPTRATE "repeat_rate"
81 #define KBD_PROP_RPTCOUNT "repeat_count"
82 #define KBD_PROP_FREQ "kbd_beeper_freq"
83 #define KBD_PROP_CONSFREQ "console_beeper_freq"
84 #define KBD_MAX_NAME_LEN 1024
85
86 char *layout_names[MAX_LAYOUT_NUM];
87 int layout_numbers[MAX_LAYOUT_NUM];
88 static int layout_count;
89 static int default_layout_number = 0;
90
91 static void reset(int);
92 static int get_type(int);
93 static void get_layout(int);
94 static void kbd_defaults(int);
95 static void usage(void);
96
97 static int click(char *, int);
98 static int abort_enable(char *, int);
99 static int set_repeat_count(char *, int);
100 static int set_rptcount(int, int);
101 static int set_repeat_delay(char *, int);
102 static int set_rptdelay(int, int);
103 static int set_repeat_rate(char *, int);
104 static int set_rptrate(int, int);
105
106 static int get_layout_number(char *);
107 static int set_layout(int, int);
108 static int get_layouts(void);
109 static int set_kbd_layout(int, char *);
110 static int set_beep_freq(int, char *, int);
111
112 int
main(int argc,char ** argv)113 main(int argc, char **argv)
114 {
115 int c, error;
116 int rflag, tflag, lflag, cflag, dflag, aflag, iflag, errflag,
117 Aflag, Dflag, Rflag, rtlacADRflag, sflag, bflag;
118 char *copt, *aopt, *count, *delay, *rate, *layout_name, *b_type;
119 char *freq_str;
120 char *kbdname = KBD_DEVICE, *endptr = NULL;
121 int kbd, freq_val;
122 extern char *optarg;
123 extern int optind;
124
125 rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag =
126 Aflag = Dflag = Rflag = sflag = bflag = 0;
127 copt = aopt = NULL;
128
129 (void) setlocale(LC_ALL, "");
130 #if !defined(TEXT_DOMAIN)
131 #define TEXT_DOMAIN "SYS_TEST"
132 #endif
133 (void) textdomain(TEXT_DOMAIN);
134
135 while ((c = getopt(argc, argv, "rtlisc:a:d:A:D:R:b:")) != EOF) {
136 switch (c) {
137 case 'r':
138 rflag++;
139 break;
140 case 't':
141 tflag++;
142 break;
143 case 'l':
144 lflag++;
145 break;
146 case 'i':
147 iflag++;
148 break;
149 case 's':
150 sflag++;
151 break;
152 case 'c':
153 copt = optarg;
154 cflag++;
155 break;
156 case 'a':
157 aopt = optarg;
158 aflag++;
159 break;
160 case 'd':
161 kbdname = optarg;
162 dflag++;
163 break;
164 case 'A':
165 count = optarg;
166 Aflag++;
167 break;
168 case 'D':
169 delay = optarg;
170 Dflag++;
171 break;
172 case 'R':
173 rate = optarg;
174 Rflag++;
175 break;
176 case 'b':
177 bflag++;
178 break;
179 case '?':
180 errflag++;
181 break;
182 }
183 }
184
185 /*
186 * Check for valid arguments:
187 *
188 * If argument parsing failed or if there are left-over
189 * command line arguments(except -s and -b option),
190 * then we're done now.
191 */
192 if (errflag != 0 || (sflag == 0 && bflag == 0 && argc != optind)) {
193 usage();
194 exit(1);
195 }
196
197 /*
198 * kbd requires that the user specify either "-i" or "-s" or "-b" or
199 * at least one of -[rtlacADR]. The "-d" option is, well, optional.
200 * We don't care if it's there or not.
201 */
202 rtlacADRflag = rflag + tflag + lflag + aflag + cflag + Aflag +
203 Dflag + Rflag;
204 if (!((iflag != 0 && sflag == 0 && bflag == 0 && rtlacADRflag == 0) ||
205 (iflag == 0 && sflag != 0 && bflag == 0 && dflag == 0 &&
206 rtlacADRflag == 0) ||
207 (iflag == 0 && sflag == 0 && bflag == 0 && rtlacADRflag != 0) ||
208 (iflag == 0 && sflag == 0 && bflag != 0 && rtlacADRflag == 0))) {
209 usage();
210 exit(1);
211 }
212
213 if (Aflag && atoi(count) < -1) {
214 (void) fprintf(stderr, "Invalid arguments: -A %s\n", count);
215 usage();
216 exit(1);
217 }
218
219 if (Dflag && atoi(delay) <= 0) {
220 (void) fprintf(stderr, "Invalid arguments: -D %s\n", delay);
221 usage();
222 exit(1);
223 }
224
225 if (Rflag && atoi(rate) <= 0) {
226 (void) fprintf(stderr, "Invalid arguments: -R %s\n", rate);
227 usage();
228 exit(1);
229 }
230
231 /*
232 * Open the keyboard device
233 */
234 if ((kbd = open(kbdname, O_RDWR)) < 0) {
235 perror("opening the keyboard");
236 (void) fprintf(stderr, "kbd: Cannot open %s\n", kbdname);
237 exit(1);
238 }
239
240 if (iflag) {
241 kbd_defaults(kbd);
242 exit(0); /* A mutually exclusive option */
243 /*NOTREACHED*/
244 }
245
246 if (tflag)
247 (void) get_type(kbd);
248
249 if (lflag)
250 get_layout(kbd);
251
252 if (cflag && (error = click(copt, kbd)) != 0)
253 exit(error);
254
255 if (rflag)
256 reset(kbd);
257
258 if (aflag && (error = abort_enable(aopt, kbd)) != 0)
259 exit(error);
260
261 if (Aflag && (error = set_repeat_count(count, kbd)) != 0)
262 exit(error);
263
264 if (Dflag && (error = set_repeat_delay(delay, kbd)) != 0)
265 exit(error);
266
267 if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0)
268 exit(error);
269
270 if (sflag) {
271 if (argc == optind) {
272 layout_name = NULL;
273 } else if (argc == (optind + 1)) {
274 layout_name = argv[optind];
275 } else {
276 usage();
277 exit(1);
278 }
279
280 if ((error = set_kbd_layout(kbd, layout_name)) != 0)
281 exit(error);
282 }
283
284 if (bflag) {
285 if (argc == optind) {
286 b_type = "keyboard";
287 } else if (argc == (optind + 1)) {
288 b_type = argv[argc - 2];
289 } else {
290 usage();
291 exit(1);
292 }
293
294 if (strcmp(b_type, "keyboard") && strcmp(b_type, "console")) {
295 usage();
296 exit(1);
297 }
298
299 freq_str = argv[argc - 1];
300 errno = 0;
301 freq_val = (int)strtol(freq_str, &endptr, 10);
302 if (errno != 0 || endptr[0] != '\0') {
303 usage();
304 exit(1);
305 }
306
307 if (freq_val < 0 || freq_val > INT16_MAX) {
308 (void) fprintf(stderr, "Invalid arguments: -b %s\n",
309 freq_str);
310 (void) fprintf(stderr, "Frequency range: [0 - %d]\n",
311 INT16_MAX);
312 exit(1);
313 }
314
315 if ((error = set_beep_freq(kbd, b_type, freq_val)) != 0)
316 exit(1);
317 }
318
319 return (0);
320 }
321
322 /*
323 * this routine gets the type of the keyboard being used
324 */
325 static int
set_kbd_layout(int kbd,char * layout_name)326 set_kbd_layout(int kbd, char *layout_name)
327 {
328 int layout_num;
329 int error = 1;
330
331 /* layout setting is possible only for USB type keyboards */
332 if (get_type(kbd) != KB_USB) {
333 (void) fprintf(stderr, "The -s option does not apply for this"
334 " keyboard type.\n"
335 "Only USB/PS2 type keyboards support this option.\n");
336 return (error);
337 }
338
339 /* get the language info from the layouts file */
340 if (get_layouts() != 0)
341 return (error);
342
343 if (layout_name != NULL) {
344 if ((layout_num = get_layout_number(layout_name)) == -1) {
345 (void) fprintf(stderr, "%s: unknown layout name\n"
346 "Please refer to 'kbd -s' to get the "
347 "supported layouts.\n", layout_name);
348 return (error);
349 }
350 } else {
351 int i, j, print_cnt, input_num;
352 boolean_t input_right = B_TRUE;
353 boolean_t default_input = B_FALSE;
354 char input[8]; /* 8 chars is enough for numbers */
355
356 print_cnt = (layout_count % 2) ?
357 layout_count/2+1 : layout_count/2;
358
359 for (i = 1; i <= print_cnt; i++) {
360 (void) printf("%2d. %-30s", i,
361 layout_names[i-1]);
362 j = i + print_cnt;
363 if (j <= layout_count) {
364 (void) printf("%-2d. %-30s\n", j,
365 layout_names[j-1]);
366 }
367 }
368 (void) printf(gettext("\nTo select the keyboard layout,"
369 " enter a number [default %d]:"),
370 default_layout_number+1);
371
372 for (;;) {
373 if (input_right == B_FALSE)
374 (void) printf(gettext("Invalid input. "
375 "Please input a number "
376 "(1,2,...):"));
377 (void) memset(input, 0, 8);
378 (void) fflush(stdin);
379 (void) fgets(input, 8, stdin);
380 if (strlen(input) > 4) {
381 input_right = B_FALSE;
382 continue;
383 }
384 if (input[0] == '\n') {
385 default_input = B_TRUE;
386 break;
387 }
388 input_right = B_TRUE;
389 /* check if the inputs are numbers 0~9 */
390 for (i = 0; i < (strlen(input) - 1); i++) {
391 if ((input[i] < '0') ||
392 (input[i] > '9')) {
393 input_right = B_FALSE;
394 break;
395 }
396 }
397 if (input_right == B_FALSE)
398 continue;
399 input_num = atoi(input);
400 if ((input_num > 0) &&
401 (input_num <= layout_count))
402 break;
403 else
404 input_right = B_FALSE;
405 }
406 if (default_input == B_TRUE)
407 layout_num = DEFAULT_KBD_LAYOUT;
408 else
409 layout_num = layout_numbers[--input_num];
410 }
411
412 if ((error = set_layout(kbd, layout_num)) != 0)
413 return (error);
414
415 return (0);
416 }
417
418 /*
419 * This routine sets keyboard or console beeper frequency
420 */
421 static int
set_beep_freq(int fd,char * type,int freq)422 set_beep_freq(int fd, char *type, int freq)
423 {
424 struct freq_request fr_struct;
425
426 if (strcmp(type, "keyboard") == 0)
427 fr_struct.type = KBD_BEEP;
428 else if (strcmp(type, "console") == 0)
429 fr_struct.type = CONSOLE_BEEP;
430 else
431 return (EINVAL);
432
433 fr_struct.freq = (int16_t)freq;
434
435 return (ioctl(fd, KIOCSETFREQ, &fr_struct));
436 }
437
438 /*
439 * this routine resets the state of the keyboard as if power-up
440 */
441 static void
reset(int kbd)442 reset(int kbd)
443 {
444 int cmd;
445
446 cmd = KBD_CMD_RESET;
447
448 if (ioctl(kbd, KIOCCMD, &cmd)) {
449 perror("kbd: ioctl error");
450 exit(1);
451 }
452
453 }
454
455 /*
456 * this routine gets the type of the keyboard being used
457 */
458 static int
get_type(int kbd)459 get_type(int kbd)
460 {
461 int kbd_type;
462
463 if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
464 perror("ioctl (kbd type)");
465 exit(1);
466 }
467
468 switch (kbd_type) {
469
470 case KB_SUN3:
471 (void) printf("Type 3 Sun keyboard\n");
472 break;
473
474 case KB_SUN4:
475 (void) printf("Type 4 Sun keyboard\n");
476 break;
477
478 case KB_ASCII:
479 (void) printf("ASCII\n");
480 break;
481
482 case KB_PC:
483 (void) printf("PC\n");
484 break;
485
486 case KB_USB:
487 (void) printf("USB keyboard\n");
488 break;
489
490 default:
491 (void) printf("Unknown keyboard type\n");
492 break;
493 }
494 return (kbd_type);
495 }
496
497 /*
498 * this routine gets the layout of the keyboard being used
499 * also, included the autorepeat delay and rate being used
500 */
501 static void
get_layout(int kbd)502 get_layout(int kbd)
503 {
504 int kbd_type;
505 int kbd_layout;
506 /* these three variables are used for getting delay&rate&count */
507 int delay, rate, count = -1;
508 delay = rate = 0;
509
510 if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
511 perror("ioctl (kbd type)");
512 exit(1);
513 }
514
515 if (ioctl(kbd, KIOCLAYOUT, &kbd_layout)) {
516 perror("ioctl (kbd layout)");
517 exit(1);
518 }
519
520 (void) printf("type=%d\nlayout=%d (0x%.2x)\n",
521 kbd_type, kbd_layout, kbd_layout);
522
523 /* below code is used to get the autorepeat delay and rate */
524 if (ioctl(kbd, KIOCGRPTDELAY, &delay)) {
525 perror("ioctl (kbd get repeat delay)");
526 exit(1);
527 }
528
529 if (ioctl(kbd, KIOCGRPTRATE, &rate)) {
530 perror("ioctl (kbd get repeat rate)");
531 exit(1);
532 }
533
534 if (ioctl(kbd, KIOCGRPTCOUNT, &count)) {
535 perror("ioctl (kbd get repeat count)");
536 exit(1);
537 }
538
539 (void) printf("delay(ms)=%d\n", delay);
540 (void) printf("rate(ms)=%d\n", rate);
541 if (count == -1)
542 (void) printf("count=unlimited\n");
543 else
544 (void) printf("count=%d\n", count);
545 }
546
547 /*
548 * this routine enables or disables clicking of the keyboard
549 */
550 static int
click(char * copt,int kbd)551 click(char *copt, int kbd)
552 {
553 int cmd;
554
555 if (strcmp(copt, "on") == 0)
556 cmd = KBD_CMD_CLICK;
557 else if (strcmp(copt, "off") == 0)
558 cmd = KBD_CMD_NOCLICK;
559 else {
560 (void) fprintf(stderr, "wrong option -- %s\n", copt);
561 usage();
562 return (1);
563 }
564
565 if (ioctl(kbd, KIOCCMD, &cmd)) {
566 perror("kbd ioctl (keyclick)");
567 return (1);
568 }
569 return (0);
570 }
571
572 /*
573 * this routine enables/disables/sets BRK or abort sequence feature
574 */
575 static int
abort_enable(char * aopt,int kbd)576 abort_enable(char *aopt, int kbd)
577 {
578 int enable;
579
580 if (strcmp(aopt, "alternate") == 0)
581 enable = KIOCABORTALTERNATE;
582 else if (strcmp(aopt, "enable") == 0)
583 enable = KIOCABORTENABLE;
584 else if (strcmp(aopt, "disable") == 0)
585 enable = KIOCABORTDISABLE;
586 else {
587 (void) fprintf(stderr, "wrong option -- %s\n", aopt);
588 usage();
589 return (1);
590 }
591
592 if (ioctl(kbd, KIOCSKABORTEN, &enable)) {
593 perror("kbd ioctl (abort enable)");
594 return (1);
595 }
596 return (0);
597 }
598
599 static int
set_rptcount(int count,int kbd)600 set_rptcount(int count, int kbd)
601 {
602 if (ioctl(kbd, KIOCSRPTCOUNT, &count) == -1) {
603 perror("kbd: set repeat count");
604 return (1);
605 }
606 return (0);
607 }
608
609 static int
set_repeat_count(char * count_str,int kbd)610 set_repeat_count(char *count_str, int kbd)
611 {
612 int count = atoi(count_str);
613
614 return (set_rptcount(count, kbd));
615 }
616
617 static int
set_rptdelay(int delay,int kbd)618 set_rptdelay(int delay, int kbd)
619 {
620 /*
621 * The error message depends on the different inputs.
622 * a. the input is a invalid integer(unit in ms)
623 * b. the input is a integer less than the minimal delay setting.
624 * The condition (a) has been covered by main function and kbd_defaults
625 * function.
626 */
627 if (ioctl(kbd, KIOCSRPTDELAY, &delay) == -1) {
628 if (delay < KIOCRPTDELAY_MIN)
629 (void) fprintf(stderr, "kbd: specified delay %d is "
630 "less than minimum %d\n", delay, KIOCRPTDELAY_MIN);
631 else
632 perror("kbd: set repeat delay");
633 return (1);
634 }
635
636 return (0);
637 }
638
639 /*
640 * this routine set autorepeat delay
641 */
642 static int
set_repeat_delay(char * delay_str,int kbd)643 set_repeat_delay(char *delay_str, int kbd)
644 {
645 int delay = atoi(delay_str);
646
647 return (set_rptdelay(delay, kbd));
648 }
649
650 static int
set_rptrate(int rate,int kbd)651 set_rptrate(int rate, int kbd)
652 {
653 /*
654 * The input validation check has been covered by main function
655 * and kbd_defaults function.Here just give an error message if
656 * the ioctl fails.
657 */
658 if (ioctl(kbd, KIOCSRPTRATE, &rate) == -1) {
659 perror("kbd: set repeat rate");
660 return (1);
661 }
662 return (0);
663 }
664
665 /*
666 * this routine set autorepeat rate
667 */
668 static int
set_repeat_rate(char * rate_str,int kbd)669 set_repeat_rate(char *rate_str, int kbd)
670 {
671 int rate = atoi(rate_str);
672
673 return (set_rptrate(rate, kbd));
674 }
675
676 #define BAD_DEFAULT_STR "kbd: bad default value for %s: %s\n"
677 #define BAD_DEFAULT_INT "kbd: bad default value for %s: %d\n"
678 #define BAD_DEFAULT_LLINT "kbd: bad default value for %s: %lld\n"
679
680 static void
kbd_defaults(int kbd)681 kbd_defaults(int kbd)
682 {
683 scf_handle_t *h = NULL;
684 scf_snapshot_t *snap = NULL;
685 scf_instance_t *inst = NULL;
686 scf_propertygroup_t *pg = NULL;
687 scf_property_t *prop = NULL;
688 scf_value_t *val = NULL;
689
690 int layout_num;
691 char *val_layout = NULL, *val_abort = NULL;
692 uint8_t val_click;
693 int64_t val_delay, val_rate, val_count;
694 int64_t val_kbd_beeper, val_console_beeper;
695
696 if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
697 scf_handle_bind(h) != 0 ||
698 (inst = scf_instance_create(h)) == NULL ||
699 (snap = scf_snapshot_create(h)) == NULL ||
700 (pg = scf_pg_create(h)) == NULL ||
701 (prop = scf_property_create(h)) == NULL ||
702 (val = scf_value_create(h)) == NULL) {
703 goto out;
704 }
705
706 if (scf_handle_decode_fmri(h, KBD_FMRI, NULL, NULL, inst,
707 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
708 goto out;
709 }
710
711 if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
712 scf_snapshot_destroy(snap);
713 snap = NULL;
714 }
715
716 if (scf_instance_get_pg_composed(inst, snap, KBD_PG, pg) != 0) {
717 goto out;
718 }
719
720 if ((val_abort = malloc(KBD_MAX_NAME_LEN)) == NULL) {
721 (void) fprintf(stderr,
722 "Can not alloc memory for keyboard properties\n");
723 goto out;
724 }
725
726 if ((val_layout = malloc(KBD_MAX_NAME_LEN)) == NULL) {
727 (void) fprintf(stderr,
728 "Can not alloc memory for keyboard properties\n");
729 goto out;
730 }
731
732 if (scf_pg_get_property(pg, KBD_PROP_KEYCLICK, prop) != 0 ||
733 scf_property_get_value(prop, val) != 0 ||
734 scf_value_get_boolean(val, &val_click) == -1) {
735 (void) fprintf(stderr, "Can not get KEYCLICK\n");
736 }
737
738 if (val_click == 1)
739 (void) click("on", kbd);
740 else if (val_click == 0)
741 (void) click("off", kbd);
742 else
743 (void) fprintf(stderr,
744 BAD_DEFAULT_INT, KBD_PROP_KEYCLICK, val_click);
745
746 if (scf_pg_get_property(pg, KBD_PROP_KEYBOARD_ABORT, prop) != 0 ||
747 scf_property_get_value(prop, val) != 0 ||
748 scf_value_get_astring(val, val_abort, KBD_MAX_NAME_LEN) == -1) {
749 (void) fprintf(stderr, "Can not get KEYBOARD_ABORT\n");
750 }
751
752 if (*val_abort != '\0') {
753 /*
754 * ABORT must equal "enable", "disable" or "alternate"
755 */
756 if ((strcmp(val_abort, "enable") == 0) ||
757 (strcmp(val_abort, "alternate") == 0) ||
758 (strcmp(val_abort, "disable") == 0))
759 (void) abort_enable(val_abort, kbd);
760 else
761 (void) fprintf(stderr, BAD_DEFAULT_STR,
762 KBD_PROP_KEYBOARD_ABORT, val_abort);
763 }
764
765 if (scf_pg_get_property(pg, KBD_PROP_RPTCOUNT, prop) != 0 ||
766 scf_property_get_value(prop, val) != 0 ||
767 scf_value_get_integer(val, &val_count) == -1) {
768 (void) fprintf(stderr, "Can not get RPTCOUNT\n");
769 }
770
771 if (val_count == -1 || (val_count > 0 && val_count < INT_MAX))
772 (void) set_rptcount(val_count, kbd);
773 else
774 (void) fprintf(stderr,
775 BAD_DEFAULT_LLINT, KBD_PROP_RPTCOUNT, val_count);
776
777 if (scf_pg_get_property(pg, KBD_PROP_RPTDELAY, prop) != 0 ||
778 scf_property_get_value(prop, val) != 0 ||
779 scf_value_get_integer(val, &val_delay) == -1) {
780 (void) fprintf(stderr, "Can not get RPTDELAY\n");
781 }
782
783 if (val_delay > 0)
784 (void) set_rptdelay(val_delay, kbd);
785 else
786 (void) fprintf(stderr,
787 BAD_DEFAULT_LLINT, KBD_PROP_RPTDELAY, val_delay);
788
789 if (scf_pg_get_property(pg, KBD_PROP_RPTRATE, prop) != 0 ||
790 scf_property_get_value(prop, val) != 0 ||
791 scf_value_get_integer(val, &val_rate) == -1) {
792 (void) fprintf(stderr, "Can not get RPTRATE\n");
793 }
794
795 if (val_rate > 0)
796 (void) set_rptrate(val_rate, kbd);
797 else
798 (void) fprintf(stderr,
799 BAD_DEFAULT_LLINT, KBD_PROP_RPTRATE, val_rate);
800
801 if (scf_pg_get_property(pg, KBD_PROP_LAYOUT, prop) != 0 ||
802 scf_property_get_value(prop, val) != 0 ||
803 scf_value_get_astring(val, val_layout, KBD_MAX_NAME_LEN) == -1) {
804 (void) fprintf(stderr, "Can not get LAYOUT\n");
805 }
806
807 if (*val_layout != '\0') {
808 /*
809 * LAYOUT must be one of the layouts supported in kbd_layouts
810 */
811 if (get_layouts() != 0)
812 goto out;
813
814 if ((layout_num = get_layout_number(val_layout)) == -1) {
815 (void) fprintf(stderr,
816 BAD_DEFAULT_STR, KBD_PROP_LAYOUT, val_layout);
817 goto out;
818 }
819
820 (void) set_layout(kbd, layout_num);
821 }
822
823 if (scf_pg_get_property(pg, KBD_PROP_FREQ, prop) != 0 ||
824 scf_property_get_value(prop, val) != 0 ||
825 scf_value_get_integer(val, &val_kbd_beeper) == -1) {
826 (void) fprintf(stderr, "Can not get FREQ\n");
827 }
828
829 if (val_kbd_beeper >= 0 && val_kbd_beeper <= INT16_MAX)
830 (void) set_beep_freq(kbd, "keyboard", val_kbd_beeper);
831 else
832 (void) fprintf(stderr,
833 BAD_DEFAULT_LLINT, KBD_PROP_FREQ, val_kbd_beeper);
834
835 if (scf_pg_get_property(pg, KBD_PROP_CONSFREQ, prop) != 0 ||
836 scf_property_get_value(prop, val) != 0 ||
837 scf_value_get_integer(val, &val_console_beeper) == -1) {
838 (void) fprintf(stderr, "Can not get CONSFREQ\n");
839 }
840
841 if (val_console_beeper >= 0 && val_console_beeper <= INT16_MAX)
842 (void) set_beep_freq(kbd, "console", val_console_beeper);
843 else
844 (void) fprintf(stderr,
845 BAD_DEFAULT_LLINT, KBD_PROP_CONSFREQ, val_console_beeper);
846
847 out:
848 if (val_layout != NULL)
849 free(val_layout);
850 if (val_abort != NULL)
851 free(val_abort);
852 if (snap != NULL)
853 scf_snapshot_destroy(snap);
854 scf_value_destroy(val);
855 scf_property_destroy(prop);
856 scf_pg_destroy(pg);
857 scf_instance_destroy(inst);
858 scf_handle_destroy(h);
859 }
860
861 static int
get_layout_number(char * layout)862 get_layout_number(char *layout)
863 {
864 int i;
865 int layout_number = -1;
866
867 for (i = 0; i < layout_count; i ++) {
868 if (strcmp(layout, layout_names[i]) == 0) {
869 layout_number = layout_numbers[i];
870 break;
871 }
872 }
873
874 return (layout_number);
875 }
876
877 static int
get_layouts()878 get_layouts()
879 {
880 FILE *stream;
881 char buffer[MAX_LINE_SIZE];
882 char *result = NULL;
883 int i = 0;
884 char *tmpbuf;
885
886 if ((stream = fopen(KBD_LAYOUT_FILE, "r")) == 0) {
887 perror(KBD_LAYOUT_FILE);
888 return (1);
889 }
890
891 while ((fgets(buffer, MAX_LINE_SIZE, stream) != NULL) &&
892 (i < MAX_LAYOUT_NUM)) {
893 if (buffer[0] == '#')
894 continue;
895 if ((result = strtok(buffer, "=")) == NULL)
896 continue;
897 if ((tmpbuf = strdup(result)) != NULL) {
898 layout_names[i] = tmpbuf;
899 } else {
900 perror("out of memory getting layout names");
901 return (1);
902 }
903 if ((result = strtok(NULL, "\n")) == NULL)
904 continue;
905 layout_numbers[i] = atoi(result);
906 if (strcmp(tmpbuf, "US-English") == 0)
907 default_layout_number = i;
908 i++;
909 }
910 layout_count = i;
911
912 return (0);
913 }
914
915 /*
916 * this routine sets the layout of the keyboard being used
917 */
918 static int
set_layout(int kbd,int layout_num)919 set_layout(int kbd, int layout_num)
920 {
921
922 if (ioctl(kbd, KIOCSLAYOUT, layout_num)) {
923 perror("ioctl (set kbd layout)");
924 return (1);
925 }
926 (void) system("/usr/bin/loadkeys");
927
928 return (0);
929 }
930
931 static char *usage1 =
932 "kbd [-r] [-t] [-l] [-a enable|disable|alternate] [-c on|off]\n"
933 "\t [-d keyboard device] [-A count] [-D delay] [-R rate]";
934 static char *usage2 = "kbd -i [-d keyboard device]";
935 static char *usage3 = "kbd -s [language]";
936 static char *usage4 = "kbd -b [keyboard|console] frequency";
937
938 static void
usage(void)939 usage(void)
940 {
941 (void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n\t%s\n", usage1,
942 usage2, usage3, usage4);
943 }
944