xref: /illumos-gate/usr/src/cmd/kbd/kbd.c (revision 33c72b7598992897b94815b1f47b7b8077e53808)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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