xref: /illumos-gate/usr/src/cmd/kbd/kbd.c (revision a386cc11a86ecb60f5a48078d22c1500e2ad003e)
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] [-D autorepeat dealy] [-R autorepeat
29  *		   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  *	-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
46  */
47 
48 #include <sys/types.h>
49 #include <sys/ioctl.h>
50 #include <sys/kbio.h>
51 #include <sys/kbd.h>
52 #include <stdio.h>
53 #include <fcntl.h>
54 #include <deflt.h>
55 #include <unistd.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <stropts.h>
59 #include <libintl.h>
60 #include <locale.h>
61 #include <errno.h>
62 #include <inttypes.h>
63 #include <libscf.h>
64 
65 #define	KBD_DEVICE	"/dev/kbd"		/* default keyboard device */
66 
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
71 
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
82 
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;
87 
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);
93 
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);
100 
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);
106 
107 int
108 main(int argc, char **argv)
109 {
110 	int c, error;
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;
115 	int kbd, freq_val;
116 	extern char *optarg;
117 	extern int optind;
118 
119 	rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag =
120 	    Dflag = Rflag = sflag = bflag = 0;
121 	copt = aopt = (char *)0;
122 
123 	(void) setlocale(LC_ALL, "");
124 #if !defined(TEXT_DOMAIN)
125 #define	TEXT_DOMAIN	"SYS_TEST"
126 #endif
127 	(void) textdomain(TEXT_DOMAIN);
128 
129 	while ((c = getopt(argc, argv, "rtlisc:a:d:D:R:b:")) != EOF) {
130 		switch (c) {
131 		case 'r':
132 			rflag++;
133 			break;
134 		case 't':
135 			tflag++;
136 			break;
137 		case 'l':
138 			lflag++;
139 			break;
140 		case 'i':
141 			iflag++;
142 			break;
143 		case 's':
144 			sflag++;
145 			break;
146 		case 'c':
147 			copt = optarg;
148 			cflag++;
149 			break;
150 		case 'a':
151 			aopt = optarg;
152 			aflag++;
153 			break;
154 		case 'd':
155 			kbdname = optarg;
156 			dflag++;
157 			break;
158 		case 'D':
159 			delay = optarg;
160 			Dflag++;
161 			break;
162 		case 'R':
163 			rate = optarg;
164 			Rflag++;
165 			break;
166 		case 'b':
167 			bflag++;
168 			break;
169 		case '?':
170 			errflag++;
171 			break;
172 		}
173 	}
174 
175 	/*
176 	 * Check for valid arguments:
177 	 *
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.
181 	 */
182 	if (errflag != 0 || (sflag == 0 && bflag == 0 && argc != optind)) {
183 		usage();
184 		exit(1);
185 	}
186 
187 	/*
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.
191 	 */
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 &&
195 	    rtlacDRflag == 0) ||
196 	    (iflag == 0 && sflag == 0 && bflag == 0 && rtlacDRflag != 0) ||
197 	    (iflag == 0 && sflag == 0 && bflag != 0 && rtlacDRflag == 0))) {
198 		usage();
199 		exit(1);
200 	}
201 
202 	if (Dflag && atoi(delay) <= 0) {
203 		(void) fprintf(stderr, "Invalid arguments: -D %s\n", delay);
204 		usage();
205 		exit(1);
206 	}
207 
208 	if (Rflag && atoi(rate) <= 0) {
209 		(void) fprintf(stderr, "Invalid arguments: -R %s\n", rate);
210 		usage();
211 		exit(1);
212 	}
213 
214 	/*
215 	 * Open the keyboard device
216 	 */
217 	if ((kbd = open(kbdname, O_RDWR)) < 0) {
218 		perror("opening the keyboard");
219 		(void) fprintf(stderr, "kbd: Cannot open %s\n", kbdname);
220 		exit(1);
221 	}
222 
223 	if (iflag) {
224 		kbd_defaults(kbd);
225 		exit(0);	/* A mutually exclusive option */
226 		/*NOTREACHED*/
227 	}
228 
229 	if (tflag)
230 		(void) get_type(kbd);
231 
232 	if (lflag)
233 		get_layout(kbd);
234 
235 	if (cflag && (error = click(copt, kbd)) != 0)
236 		exit(error);
237 
238 	if (rflag)
239 		reset(kbd);
240 
241 	if (aflag && (error = abort_enable(aopt, kbd)) != 0)
242 		exit(error);
243 
244 	if (Dflag && (error = set_repeat_delay(delay, kbd)) != 0)
245 		exit(error);
246 
247 	if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0)
248 		exit(error);
249 
250 	if (sflag) {
251 		if (argc == optind) {
252 			layout_name = NULL;
253 		} else if (argc == (optind + 1)) {
254 			layout_name = argv[optind];
255 		} else {
256 			usage();
257 			exit(1);
258 		}
259 
260 		if ((error = set_kbd_layout(kbd, layout_name)) != 0)
261 			exit(error);
262 	}
263 
264 	if (bflag) {
265 		if (argc == optind) {
266 			b_type = "keyboard";
267 		} else if (argc == (optind + 1)) {
268 			b_type = argv[argc - 2];
269 		} else {
270 			usage();
271 			exit(1);
272 		}
273 
274 		if (strcmp(b_type, "keyboard") && strcmp(b_type, "console")) {
275 			usage();
276 			exit(1);
277 		}
278 
279 		freq_str = argv[argc - 1];
280 		errno = 0;
281 		freq_val = (int)strtol(freq_str, &endptr, 10);
282 		if (errno != 0 || endptr[0] != '\0') {
283 			usage();
284 			exit(1);
285 		}
286 
287 		if (freq_val < 0 || freq_val > INT16_MAX) {
288 			(void) fprintf(stderr, "Invalid arguments: -b %s\n",
289 			    freq_str);
290 			(void) fprintf(stderr, "Frequency range: [0 - %d]\n",
291 			    INT16_MAX);
292 			exit(1);
293 		}
294 
295 		if ((error = set_beep_freq(kbd, b_type, freq_val)) != 0)
296 			exit(1);
297 	}
298 
299 	return (0);
300 }
301 
302 /*
303  * this routine gets the type of the keyboard being used
304  */
305 static int
306 set_kbd_layout(int kbd, char *layout_name)
307 {
308 	int layout_num;
309 	int error = 1;
310 
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"
314 		    " keyboard type.\n"
315 		    "Only USB/PS2 type keyboards support this option.\n");
316 		return (error);
317 	}
318 
319 	/* get the language info from the layouts file */
320 	if (get_layouts() != 0)
321 		return (error);
322 
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);
328 			return (error);
329 		}
330 	} else {
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 */
335 
336 			print_cnt = (layout_count % 2) ?
337 			    layout_count/2+1 : layout_count/2;
338 
339 			for (i = 1; i <= print_cnt; i++) {
340 				(void) printf("%2d. %-30s", i,
341 				    layout_names[i-1]);
342 				j = i + print_cnt;
343 				if (j <= layout_count) {
344 					(void) printf("%-2d. %-30s\n", j,
345 					    layout_names[j-1]);
346 				}
347 			}
348 			(void) printf(gettext("\nTo select the keyboard layout,"
349 			    " enter a number [default %d]:"),
350 			    default_layout_number+1);
351 
352 			for (;;) {
353 				if (input_right == B_FALSE)
354 					(void) printf(gettext("Invalid input. "
355 					    "Please input a number "
356 					    "(1,2,...):"));
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;
362 					continue;
363 				}
364 				if (input[0] == '\n') {
365 					default_input = B_TRUE;
366 					break;
367 				}
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') ||
372 					    (input[i] > '9')) {
373 						input_right = B_FALSE;
374 						break;
375 					}
376 				}
377 				if (input_right == B_FALSE)
378 					continue;
379 				input_num = atoi(input);
380 				if ((input_num > 0) &&
381 				    (input_num <= layout_count))
382 					break;
383 				else
384 					input_right = B_FALSE;
385 			}
386 			if (default_input == B_TRUE)
387 				layout_num = DEFAULT_KBD_LAYOUT;
388 			else
389 				layout_num = layout_numbers[--input_num];
390 	}
391 
392 	if ((error = set_layout(kbd, layout_num)) != 0)
393 		return (error);
394 
395 	return (0);
396 }
397 
398 /*
399  * This routine sets keyboard or console beeper frequency
400  */
401 static int
402 set_beep_freq(int fd, char *type, int freq)
403 {
404 	struct freq_request fr_struct;
405 
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;
410 	else
411 		return (EINVAL);
412 
413 	fr_struct.freq = (int16_t)freq;
414 
415 	return (ioctl(fd, KIOCSETFREQ, &fr_struct));
416 }
417 
418 /*
419  * this routine resets the state of the keyboard as if power-up
420  */
421 static void
422 reset(int kbd)
423 {
424 	int cmd;
425 
426 	cmd = KBD_CMD_RESET;
427 
428 	if (ioctl(kbd, KIOCCMD, &cmd)) {
429 		perror("kbd: ioctl error");
430 		exit(1);
431 	}
432 
433 }
434 
435 /*
436  * this routine gets the type of the keyboard being used
437  */
438 static int
439 get_type(int kbd)
440 {
441 	int kbd_type;
442 
443 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
444 		perror("ioctl (kbd type)");
445 		exit(1);
446 	}
447 
448 	switch (kbd_type) {
449 
450 	case KB_SUN3:
451 		(void) printf("Type 3 Sun keyboard\n");
452 		break;
453 
454 	case KB_SUN4:
455 		(void) printf("Type 4 Sun keyboard\n");
456 		break;
457 
458 	case KB_ASCII:
459 		(void) printf("ASCII\n");
460 		break;
461 
462 	case KB_PC:
463 		(void) printf("PC\n");
464 		break;
465 
466 	case KB_USB:
467 		(void) printf("USB keyboard\n");
468 		break;
469 
470 	default:
471 		(void) printf("Unknown keyboard type\n");
472 		break;
473 	}
474 	return (kbd_type);
475 }
476 
477 /*
478  * this routine gets the layout of the keyboard being used
479  * also, included the autorepeat delay and rate being used
480  */
481 static void
482 get_layout(int kbd)
483 {
484 	int kbd_type;
485 	int kbd_layout;
486 	/* these two variables are used for getting delay&rate */
487 	int delay, rate;
488 	delay = rate = 0;
489 
490 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
491 		perror("ioctl (kbd type)");
492 		exit(1);
493 	}
494 
495 	if (ioctl(kbd, KIOCLAYOUT, &kbd_layout)) {
496 		perror("ioctl (kbd layout)");
497 		exit(1);
498 	}
499 
500 	(void) printf("type=%d\nlayout=%d (0x%.2x)\n",
501 	    kbd_type, kbd_layout, kbd_layout);
502 
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)");
506 		exit(1);
507 	}
508 
509 	if (ioctl(kbd, KIOCGRPTRATE, &rate)) {
510 		perror("ioctl (kbd get repeat rate)");
511 		exit(1);
512 	}
513 
514 	(void) printf("delay(ms)=%d\n", delay);
515 	(void) printf("rate(ms)=%d\n", rate);
516 }
517 
518 /*
519  * this routine enables or disables clicking of the keyboard
520  */
521 static int
522 click(char *copt, int kbd)
523 {
524 	int cmd;
525 
526 	if (strcmp(copt, "on") == 0)
527 		cmd = KBD_CMD_CLICK;
528 	else if (strcmp(copt, "off") == 0)
529 		cmd = KBD_CMD_NOCLICK;
530 	else {
531 		(void) fprintf(stderr, "wrong option -- %s\n", copt);
532 		usage();
533 		return (1);
534 	}
535 
536 	if (ioctl(kbd, KIOCCMD, &cmd)) {
537 		perror("kbd ioctl (keyclick)");
538 		return (1);
539 	}
540 	return (0);
541 }
542 
543 /*
544  * this routine enables/disables/sets BRK or abort sequence feature
545  */
546 static int
547 abort_enable(char *aopt, int kbd)
548 {
549 	int enable;
550 
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;
557 	else {
558 		(void) fprintf(stderr, "wrong option -- %s\n", aopt);
559 		usage();
560 		return (1);
561 	}
562 
563 	if (ioctl(kbd, KIOCSKABORTEN, &enable)) {
564 		perror("kbd ioctl (abort enable)");
565 		return (1);
566 	}
567 	return (0);
568 }
569 
570 static int
571 set_rptdelay(int delay, int kbd)
572 {
573 	/*
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
578 	 * function.
579 	 */
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);
584 		else
585 			perror("kbd: set repeat delay");
586 		return (1);
587 	}
588 
589 	return (0);
590 }
591 
592 /*
593  * this routine set autorepeat delay
594  */
595 static int
596 set_repeat_delay(char *delay_str, int kbd)
597 {
598 	int delay = atoi(delay_str);
599 
600 	return (set_rptdelay(delay, kbd));
601 }
602 
603 static int
604 set_rptrate(int rate, int kbd)
605 {
606 	/*
607 	 * The input validation check has been covered by main function
608 	 * and kbd_defaults function.Here just give an error message if
609 	 * the ioctl fails.
610 	 */
611 	if (ioctl(kbd, KIOCSRPTRATE, &rate) == -1) {
612 		perror("kbd: set repeat rate");
613 		return (1);
614 	}
615 	return (0);
616 }
617 
618 /*
619  * this routine set autorepeat rate
620  */
621 static int
622 set_repeat_rate(char *rate_str, int kbd)
623 {
624 	int rate = atoi(rate_str);
625 
626 	return (set_rptrate(rate, kbd));
627 }
628 
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"
632 
633 static void
634 kbd_defaults(int kbd)
635 {
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;
642 
643 	int layout_num;
644 	char *val_layout = NULL, *val_abort = NULL;
645 	uint8_t val_click;
646 	int64_t val_delay, val_rate;
647 	int64_t val_kbd_beeper, val_console_beeper;
648 
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) {
656 		goto out;
657 	}
658 
659 	if (scf_handle_decode_fmri(h, KBD_FMRI, NULL, NULL, inst,
660 	    NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
661 		goto out;
662 	}
663 
664 	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
665 		scf_snapshot_destroy(snap);
666 		snap = NULL;
667 	}
668 
669 	if (scf_instance_get_pg_composed(inst, snap, KBD_PG, pg) != 0) {
670 		goto out;
671 	}
672 
673 	if ((val_abort = malloc(KBD_MAX_NAME_LEN)) == NULL) {
674 		(void) fprintf(stderr,
675 		    "Can not alloc memory for keyboard properties\n");
676 		goto out;
677 	}
678 
679 	if ((val_layout = malloc(KBD_MAX_NAME_LEN)) == NULL) {
680 		(void) fprintf(stderr,
681 		    "Can not alloc memory for keyboard properties\n");
682 		goto out;
683 	}
684 
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");
689 	}
690 
691 	if (val_click == 1)
692 		(void) click("on", kbd);
693 	else if (val_click == 0)
694 		(void) click("off", kbd);
695 	else
696 		(void) fprintf(stderr,
697 		    BAD_DEFAULT_INT, KBD_PROP_KEYCLICK, val_click);
698 
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");
703 	}
704 
705 	if (*val_abort != '\0') {
706 		/*
707 		 * ABORT must equal "enable", "disable" or "alternate"
708 		 */
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);
713 		else
714 			(void) fprintf(stderr, BAD_DEFAULT_STR,
715 			    KBD_PROP_KEYBOARD_ABORT, val_abort);
716 	}
717 
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");
722 	}
723 
724 	if (val_delay > 0)
725 		(void) set_rptdelay(val_delay, kbd);
726 	else
727 		(void) fprintf(stderr,
728 		    BAD_DEFAULT_LLINT, KBD_PROP_RPTDELAY, val_delay);
729 
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");
734 	}
735 
736 	if (val_rate > 0)
737 		(void) set_rptrate(val_rate, kbd);
738 	else
739 		(void) fprintf(stderr,
740 		    BAD_DEFAULT_LLINT, KBD_PROP_RPTRATE, val_rate);
741 
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");
746 	}
747 
748 	if (*val_layout != '\0') {
749 		/*
750 		 * LAYOUT must be one of the layouts supported in kbd_layouts
751 		 */
752 		if (get_layouts() != 0)
753 			goto out;
754 
755 		if ((layout_num = get_layout_number(val_layout)) == -1) {
756 			(void) fprintf(stderr,
757 			    BAD_DEFAULT_STR, KBD_PROP_LAYOUT, val_layout);
758 			goto out;
759 		}
760 
761 		(void) set_layout(kbd, layout_num);
762 	}
763 
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");
768 	}
769 
770 	if (val_kbd_beeper >= 0 && val_kbd_beeper <= INT16_MAX)
771 		(void) set_beep_freq(kbd, "keyboard", val_kbd_beeper);
772 	else
773 		(void) fprintf(stderr,
774 		    BAD_DEFAULT_LLINT, KBD_PROP_FREQ, val_kbd_beeper);
775 
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");
780 	}
781 
782 	if (val_console_beeper >= 0 && val_console_beeper <= INT16_MAX)
783 		(void) set_beep_freq(kbd, "console", val_console_beeper);
784 	else
785 		(void) fprintf(stderr,
786 		    BAD_DEFAULT_LLINT, KBD_PROP_CONSFREQ, val_console_beeper);
787 
788 out:
789 	if (val_layout != NULL)
790 		free(val_layout);
791 	if (val_abort != NULL)
792 		free(val_abort);
793 	if (snap != NULL)
794 		scf_snapshot_destroy(snap);
795 	scf_value_destroy(val);
796 	scf_property_destroy(prop);
797 	scf_pg_destroy(pg);
798 	scf_instance_destroy(inst);
799 	scf_handle_destroy(h);
800 }
801 
802 static int
803 get_layout_number(char *layout)
804 {
805 	int i;
806 	int layout_number = -1;
807 
808 	for (i = 0; i < layout_count; i ++) {
809 		if (strcmp(layout, layout_names[i]) == 0) {
810 			layout_number = layout_numbers[i];
811 			break;
812 		}
813 	}
814 
815 	return (layout_number);
816 }
817 
818 static int
819 get_layouts()
820 {
821 	FILE *stream;
822 	char buffer[MAX_LINE_SIZE];
823 	char *result = NULL;
824 	int  i = 0;
825 	char *tmpbuf;
826 
827 	if ((stream = fopen(KBD_LAYOUT_FILE, "r")) == 0) {
828 		perror(KBD_LAYOUT_FILE);
829 		return (1);
830 	}
831 
832 	while ((fgets(buffer, MAX_LINE_SIZE, stream) != NULL) &&
833 	    (i < MAX_LAYOUT_NUM)) {
834 		if (buffer[0] == '#')
835 			continue;
836 		if ((result = strtok(buffer, "=")) == NULL)
837 			continue;
838 		if ((tmpbuf = strdup(result)) != NULL) {
839 			layout_names[i] = tmpbuf;
840 		} else {
841 			perror("out of memory getting layout names");
842 			return (1);
843 		}
844 		if ((result = strtok(NULL, "\n")) == NULL)
845 			continue;
846 		layout_numbers[i] = atoi(result);
847 		if (strcmp(tmpbuf, "US-English") == 0)
848 			default_layout_number = i;
849 		i++;
850 	}
851 	layout_count = i;
852 
853 	return (0);
854 }
855 
856 /*
857  * this routine sets the layout of the keyboard being used
858  */
859 static int
860 set_layout(int kbd, int layout_num)
861 {
862 
863 	if (ioctl(kbd, KIOCSLAYOUT, layout_num)) {
864 		perror("ioctl (set kbd layout)");
865 		return (1);
866 	}
867 
868 	return (0);
869 }
870 
871 static char *usage1 = "kbd [-r] [-t] [-l] [-a enable|disable|alternate]";
872 static char *usage2 = "    [-c on|off][-D delay][-R rate][-d keyboard device]";
873 static char *usage3 = "kbd -i [-d keyboard device]";
874 static char *usage4 = "kbd -s [language]";
875 static char *usage5 = "kbd -b [keyboard|console] frequency";
876 
877 static void
878 usage(void)
879 {
880 	(void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", usage1,
881 	    usage2, usage3, usage4, usage5);
882 }
883