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
83char *layout_names[MAX_LAYOUT_NUM];
84int layout_numbers[MAX_LAYOUT_NUM];
85static int layout_count;
86static int default_layout_number = 0;
87
88static void reset(int);
89static int get_type(int);
90static void get_layout(int);
91static void kbd_defaults(int);
92static void usage(void);
93
94static int click(char *, int);
95static int abort_enable(char *, int);
96static int set_repeat_delay(char *, int);
97static int set_rptdelay(int, int);
98static int set_repeat_rate(char *, int);
99static int set_rptrate(int, int);
100
101static int get_layout_number(char *);
102static int set_layout(int, int);
103static int get_layouts(void);
104static int set_kbd_layout(int, char *);
105static int set_beep_freq(int, char *, int);
106
107int
108main(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 */
305static int
306set_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 */
401static int
402set_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 */
421static void
422reset(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 */
438static int
439get_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 */
481static void
482get_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 */
521static int
522click(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 */
546static int
547abort_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
570static int
571set_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 */
595static int
596set_repeat_delay(char *delay_str, int kbd)
597{
598	int delay = atoi(delay_str);
599
600	return (set_rptdelay(delay, kbd));
601}
602
603static int
604set_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 */
621static int
622set_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
633static void
634kbd_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
788out:
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
802static int
803get_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
818static int
819get_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 */
859static int
860set_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
871static char *usage1 = "kbd [-r] [-t] [-l] [-a enable|disable|alternate]";
872static char *usage2 = "    [-c on|off][-D delay][-R rate][-d keyboard device]";
873static char *usage3 = "kbd -i [-d keyboard device]";
874static char *usage4 = "kbd -s [language]";
875static char *usage5 = "kbd -b [keyboard|console] frequency";
876
877static void
878usage(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