xref: /illumos-gate/usr/src/cmd/kbd/kbd.c (revision 63360950109af2ce85a962ca61f40b8782f11100)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 
29 /*
30  *	Usage: kbd [-r] [-t] [-l] [-c on|off] [-a enable|disable|alternate]
31  *		   [-d keyboard device] [-D autorepeat dealy] [-R autorepeat
32  *		   rate]
33  *	       kbd [-i] [-d keyboard device]
34  *	       kbd -s [language]
35  *	       kbd -b [keyboard|console] frequency
36  *	-r			reset the keyboard as if power-up
37  *	-t			return the type of the keyboard being used
38  *	-l			return the layout of the keyboard being used,
39  *				and the Autorepeat settings
40  *	-i			read in the default configuration file
41  *	-c on|off		turn on|off clicking
42  *	-a enable|disable|alternate	sets abort sequence
43  *	-D autorepeat delay	sets autorepeat dealy, unit in ms
44  *	-R autorepeat rate	sets autorepeat rate, unit in ms
45  *	-d keyboard device	chooses the kbd device, default /dev/kbd.
46  *	-s keyboard layout	sets keyboard layout
47  *	-b [keyboard| console]	frequency
48  *				sets keyboard or console beeper frequency
49  */
50 
51 #include <sys/types.h>
52 #include <sys/ioctl.h>
53 #include <sys/kbio.h>
54 #include <sys/kbd.h>
55 #include <stdio.h>
56 #include <fcntl.h>
57 #include <deflt.h>
58 #include <unistd.h>
59 #include <string.h>
60 #include <stdlib.h>
61 #include <stropts.h>
62 #include <libintl.h>
63 #include <locale.h>
64 #include <errno.h>
65 #include <inttypes.h>
66 
67 #define	KBD_DEVICE	"/dev/kbd"		/* default keyboard device */
68 #define	DEF_FILE	"/etc/default/kbd"	/* kbd defaults file	*/
69 #define	DEF_ABORT	"KEYBOARD_ABORT="
70 #define	DEF_CLICK	"KEYCLICK="
71 #define	DEF_RPTDELAY	"REPEAT_DELAY="
72 #define	DEF_RPTRATE	"REPEAT_RATE="
73 #define	DEF_LAYOUT	"LAYOUT="
74 #define	DEF_KBDFREQ	"KBD_BEEPER_FREQ="
75 #define	DEF_CONSFREQ	"CONSOLE_BEEPER_FREQ="
76 
77 #define	KBD_LAYOUT_FILE  "/usr/share/lib/keytables/type_6/kbd_layouts"
78 #define	MAX_LAYOUT_NUM		128
79 #define	MAX_LINE_SIZE		256
80 #define	DEFAULT_KBD_LAYOUT	33
81 
82 int errno;
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 void 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_repeat_rate(char *, int);
98 
99 static int get_layout_number(char *);
100 static int set_layout(int, int);
101 static int get_layouts(void);
102 static int set_kbd_layout(int, char *);
103 static int set_beep_freq(int, char *, int);
104 
105 int
106 main(int argc, char **argv)
107 {
108 	int c, error;
109 	int rflag, tflag, lflag, cflag, dflag, aflag, iflag, errflag,
110 	    Dflag, Rflag, rtlacDRflag, sflag, bflag;
111 	char *copt, *aopt, *delay, *rate, *layout_name, *b_type, *freq_str;
112 	char *kbdname = KBD_DEVICE, *endptr = NULL;
113 	int kbd, freq_val;
114 	extern char *optarg;
115 	extern int optind;
116 
117 	rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag =
118 	    Dflag = Rflag = sflag = bflag = 0;
119 	copt = aopt = (char *)0;
120 
121 	(void) setlocale(LC_ALL, "");
122 #if !defined(TEXT_DOMAIN)
123 #define	TEXT_DOMAIN	"SYS_TEST"
124 #endif
125 	(void) textdomain(TEXT_DOMAIN);
126 
127 	while ((c = getopt(argc, argv, "rtlisc:a:d:D:R:b:")) != EOF) {
128 		switch (c) {
129 		case 'r':
130 			rflag++;
131 			break;
132 		case 't':
133 			tflag++;
134 			break;
135 		case 'l':
136 			lflag++;
137 			break;
138 		case 'i':
139 			iflag++;
140 			break;
141 		case 's':
142 			sflag++;
143 			break;
144 		case 'c':
145 			copt = optarg;
146 			cflag++;
147 			break;
148 		case 'a':
149 			aopt = optarg;
150 			aflag++;
151 			break;
152 		case 'd':
153 			kbdname = optarg;
154 			dflag++;
155 			break;
156 		case 'D':
157 			delay = optarg;
158 			Dflag++;
159 			break;
160 		case 'R':
161 			rate = optarg;
162 			Rflag++;
163 			break;
164 		case 'b':
165 			bflag++;
166 			break;
167 		case '?':
168 			errflag++;
169 			break;
170 		}
171 	}
172 
173 	/*
174 	 * Check for valid arguments:
175 	 *
176 	 * If argument parsing failed or if there are left-over
177 	 * command line arguments(except -s and -b option),
178 	 * then we're done now.
179 	 */
180 	if (errflag != 0 || (sflag == 0 && bflag == 0 && argc != optind)) {
181 		usage();
182 		exit(1);
183 	}
184 
185 	/*
186 	 * kbd requires that the user specify either "-i" or "-s" or "-b" or
187 	 * at least one of -[rtlacDR].  The "-d" option is, well, optional.
188 	 * We don't care if it's there or not.
189 	 */
190 	rtlacDRflag = rflag + tflag + lflag + aflag + cflag + Dflag + Rflag;
191 	if (!((iflag != 0 && sflag == 0 && bflag == 0 && rtlacDRflag == 0) ||
192 	    (iflag == 0 && sflag != 0 && bflag == 0 && dflag == 0 &&
193 	    rtlacDRflag == 0) ||
194 	    (iflag == 0 && sflag == 0 && bflag == 0 && rtlacDRflag != 0) ||
195 	    (iflag == 0 && sflag == 0 && bflag != 0 && rtlacDRflag == 0))) {
196 		usage();
197 		exit(1);
198 	}
199 
200 	if (Dflag && atoi(delay) <= 0) {
201 		(void) fprintf(stderr, "Invalid arguments: -D %s\n", delay);
202 		usage();
203 		exit(1);
204 	}
205 
206 	if (Rflag && atoi(rate) <= 0) {
207 		(void) fprintf(stderr, "Invalid arguments: -R %s\n", rate);
208 		usage();
209 		exit(1);
210 	}
211 
212 	/*
213 	 * Open the keyboard device
214 	 */
215 	if ((kbd = open(kbdname, O_RDWR)) < 0) {
216 		perror("opening the keyboard");
217 		(void) fprintf(stderr, "kbd: Cannot open %s\n", kbdname);
218 		exit(1);
219 	}
220 
221 	if (iflag) {
222 		kbd_defaults(kbd);
223 		exit(0);	/* A mutually exclusive option */
224 		/*NOTREACHED*/
225 	}
226 
227 	if (tflag)
228 		get_type(kbd);
229 
230 	if (lflag)
231 		get_layout(kbd);
232 
233 	if (cflag && (error = click(copt, kbd)) != 0)
234 		exit(error);
235 
236 	if (rflag)
237 		reset(kbd);
238 
239 	if (aflag && (error = abort_enable(aopt, kbd)) != 0)
240 		exit(error);
241 
242 	if (Dflag && (error = set_repeat_delay(delay, kbd)) != 0)
243 		exit(error);
244 
245 	if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0)
246 		exit(error);
247 
248 	if (sflag) {
249 		if (argc == optind) {
250 			layout_name = NULL;
251 		} else if (argc == (optind + 1)) {
252 			layout_name = argv[optind];
253 		} else {
254 			usage();
255 			exit(1);
256 		}
257 
258 		if ((error = set_kbd_layout(kbd, layout_name)) != 0)
259 			exit(error);
260 	}
261 
262 	if (bflag) {
263 		if (argc == optind) {
264 			b_type = "keyboard";
265 		} else if (argc == (optind + 1)) {
266 			b_type = argv[argc - 2];
267 		} else {
268 			usage();
269 			exit(1);
270 		}
271 
272 		if (strcmp(b_type, "keyboard") && strcmp(b_type, "console")) {
273 			usage();
274 			exit(1);
275 		}
276 
277 		freq_str = argv[argc - 1];
278 		errno = 0;
279 		freq_val = (int)strtol(freq_str, &endptr, 10);
280 		if (errno != 0 || endptr[0] != '\0') {
281 			usage();
282 			exit(1);
283 		}
284 
285 		if (freq_val < 0 || freq_val > INT16_MAX) {
286 			(void) fprintf(stderr, "Invalid arguments: -b %s\n",
287 			    freq_str);
288 			(void) fprintf(stderr, "Frequency range: [0 - %d]\n",
289 			    INT16_MAX);
290 			exit(1);
291 		}
292 
293 		if ((error = set_beep_freq(kbd, b_type, freq_val)) != 0)
294 			exit(1);
295 	}
296 
297 	return (0);
298 }
299 
300 /*
301  * this routine gets the type of the keyboard being used
302  */
303 static int
304 set_kbd_layout(int kbd, char *layout_name)
305 {
306 	int layout_num;
307 	int error = 1;
308 
309 	/* get the language info from the layouts file */
310 	if (get_layouts() != 0)
311 		return (error);
312 
313 	if (layout_name != NULL) {
314 		if ((layout_num = get_layout_number(layout_name)) == -1) {
315 			(void) fprintf(stderr, "%s: unknown layout name\n"
316 				    "Please refer to 'kbd -s' to get the "
317 				    "supported layouts.\n", layout_name);
318 			return (error);
319 		}
320 	} else {
321 			int i, j, print_cnt, input_num;
322 			boolean_t input_right = B_TRUE;
323 			boolean_t default_input = B_FALSE;
324 			char input[8]; /* 8 chars is enough for numbers */
325 
326 			print_cnt = (layout_count % 2) ?
327 				layout_count/2+1 : layout_count/2;
328 
329 			for (i = 1; i <= print_cnt; i++) {
330 				(void) printf("%2d. %-30s", i,
331 					    layout_names[i-1]);
332 				j = i + print_cnt;
333 				if (j <= layout_count) {
334 					(void) printf("%-2d. %-30s\n", j,
335 						    layout_names[j-1]);
336 				}
337 			}
338 			(void) printf(gettext("\nTo select the keyboard layout,"
339 				    " enter a number [default %d]:"),
340 				    default_layout_number+1);
341 
342 			for (;;) {
343 				if (input_right == B_FALSE)
344 					(void) printf(gettext("Invalid input. "
345 					    "Please input a number "
346 					    "(1,2,...):"));
347 				(void) memset(input, 0, 8);
348 				(void) fflush(stdin);
349 				(void) fgets(input, 8, stdin);
350 				if (strlen(input) > 4) {
351 					input_right = B_FALSE;
352 					continue;
353 				}
354 				if (input[0] == '\n') {
355 					default_input = B_TRUE;
356 					break;
357 				}
358 				input_right = B_TRUE;
359 				/* check if the inputs are numbers 0~9 */
360 				for (i = 0; i < (strlen(input) - 1); i++) {
361 					if ((input[i] < '0') ||
362 					    (input[i] > '9')) {
363 						input_right = B_FALSE;
364 						break;
365 					}
366 				}
367 				if (input_right == B_FALSE)
368 					continue;
369 				input_num = atoi(input);
370 				if ((input_num > 0) &&
371 				    (input_num <= layout_count))
372 					break;
373 				else
374 					input_right = B_FALSE;
375 			}
376 			if (default_input == B_TRUE)
377 				layout_num = DEFAULT_KBD_LAYOUT;
378 			else
379 				layout_num = layout_numbers[--input_num];
380 	}
381 
382 	if ((error = set_layout(kbd, layout_num)) != 0)
383 		return (error);
384 
385 	return (0);
386 }
387 
388 /*
389  * This routine sets keyboard or console beeper frequency
390  */
391 static int
392 set_beep_freq(int fd, char *type, int freq)
393 {
394 	struct freq_request fr_struct;
395 
396 	if (strcmp(type, "keyboard") == 0)
397 		fr_struct.type = KBD_BEEP;
398 	else if (strcmp(type, "console") == 0)
399 		fr_struct.type = CONSOLE_BEEP;
400 	else
401 		return (EINVAL);
402 
403 	fr_struct.freq = (int16_t)freq;
404 
405 	return (ioctl(fd, KIOCSETFREQ, &fr_struct));
406 }
407 
408 /*
409  * this routine resets the state of the keyboard as if power-up
410  */
411 static void
412 reset(int kbd)
413 {
414 	int cmd;
415 
416 	cmd = KBD_CMD_RESET;
417 
418 	if (ioctl(kbd, KIOCCMD, &cmd)) {
419 		perror("kbd: ioctl error");
420 		exit(1);
421 	}
422 
423 }
424 
425 /*
426  * this routine gets the type of the keyboard being used
427  */
428 static void
429 get_type(int kbd)
430 {
431 	int kbd_type;
432 
433 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
434 		perror("ioctl (kbd type)");
435 		exit(1);
436 	}
437 
438 	switch (kbd_type) {
439 
440 	case KB_SUN3:
441 		(void) printf("Type 3 Sun keyboard\n");
442 		break;
443 
444 	case KB_SUN4:
445 		(void) printf("Type 4 Sun keyboard\n");
446 		break;
447 
448 	case KB_ASCII:
449 		(void) printf("ASCII\n");
450 		break;
451 
452 	case KB_PC:
453 		(void) printf("PC\n");
454 		break;
455 
456 	case KB_USB:
457 		(void) printf("USB keyboard\n");
458 		break;
459 
460 	default:
461 		(void) printf("Unknown keyboard type\n");
462 		break;
463 	}
464 }
465 
466 /*
467  * this routine gets the layout of the keyboard being used
468  * also, included the autorepeat delay and rate being used
469  */
470 static void
471 get_layout(int kbd)
472 {
473 	int kbd_type;
474 	int kbd_layout;
475 	/* these two variables are used for getting delay&rate */
476 	int delay, rate;
477 	delay = rate = 0;
478 
479 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
480 		perror("ioctl (kbd type)");
481 		exit(1);
482 	}
483 
484 	if (ioctl(kbd, KIOCLAYOUT, &kbd_layout)) {
485 		perror("ioctl (kbd layout)");
486 		exit(1);
487 	}
488 
489 	(void) printf("type=%d\nlayout=%d (0x%.2x)\n",
490 	    kbd_type, kbd_layout, kbd_layout);
491 
492 	/* below code is used to get the autorepeat delay and rate */
493 	if (ioctl(kbd, KIOCGRPTDELAY, &delay)) {
494 		perror("ioctl (kbd get repeat delay)");
495 		exit(1);
496 	}
497 
498 	if (ioctl(kbd, KIOCGRPTRATE, &rate)) {
499 		perror("ioctl (kbd get repeat rate)");
500 		exit(1);
501 	}
502 
503 	(void) printf("delay(ms)=%d\n", delay);
504 	(void) printf("rate(ms)=%d\n", rate);
505 }
506 
507 /*
508  * this routine enables or disables clicking of the keyboard
509  */
510 static int
511 click(char *copt, int kbd)
512 {
513 	int cmd;
514 
515 	if (strcmp(copt, "on") == 0)
516 		cmd = KBD_CMD_CLICK;
517 	else if (strcmp(copt, "off") == 0)
518 		cmd = KBD_CMD_NOCLICK;
519 	else {
520 		(void) fprintf(stderr, "wrong option -- %s\n", copt);
521 		usage();
522 		return (1);
523 	}
524 
525 	if (ioctl(kbd, KIOCCMD, &cmd)) {
526 		perror("kbd ioctl (keyclick)");
527 		return (1);
528 	}
529 	return (0);
530 }
531 
532 /*
533  * this routine enables/disables/sets BRK or abort sequence feature
534  */
535 static int
536 abort_enable(char *aopt, int kbd)
537 {
538 	int enable;
539 
540 	if (strcmp(aopt, "alternate") == 0)
541 		enable = KIOCABORTALTERNATE;
542 	else if (strcmp(aopt, "enable") == 0)
543 		enable = KIOCABORTENABLE;
544 	else if (strcmp(aopt, "disable") == 0)
545 		enable = KIOCABORTDISABLE;
546 	else {
547 		(void) fprintf(stderr, "wrong option -- %s\n", aopt);
548 		usage();
549 		return (1);
550 	}
551 
552 	if (ioctl(kbd, KIOCSKABORTEN, &enable)) {
553 		perror("kbd ioctl (abort enable)");
554 		return (1);
555 	}
556 	return (0);
557 }
558 
559 /*
560  * this routine set autorepeat delay
561  */
562 static int
563 set_repeat_delay(char *delay_str, int kbd)
564 {
565 	int delay = atoi(delay_str);
566 
567 	/*
568 	 * The error message depends on the different inputs.
569 	 * a. the input is a invalid integer(unit in ms)
570 	 * b. the input is a integer less than the minimal delay setting.
571 	 * The condition (a) has been covered by main function and set_default
572 	 * function.
573 	 */
574 	if (ioctl(kbd, KIOCSRPTDELAY, &delay) == -1) {
575 		if (delay < KIOCRPTDELAY_MIN)
576 			(void) fprintf(stderr, "kbd: specified delay %d is "
577 			    "less than minimum %d\n", delay, KIOCRPTDELAY_MIN);
578 		else
579 			perror("kbd: set repeat delay");
580 		return (1);
581 	}
582 
583 	return (0);
584 }
585 
586 /*
587  * this routine set autorepeat rate
588  */
589 static int
590 set_repeat_rate(char *rate_str, int kbd)
591 {
592 	int rate = atoi(rate_str);
593 
594 	/*
595 	 * The error message depends on the different inputs.
596 	 * a. the input is a invalid integer(unit in ms)
597 	 * b. the input is a integer less than the minimal rate setting.
598 	 * The condition (a) has been covered by main function and set_default
599 	 * function.
600 	 */
601 	if (ioctl(kbd, KIOCSRPTRATE, &rate) == -1) {
602 		if (rate < KIOCRPTRATE_MIN)
603 			(void) fprintf(stderr, "kbd: specified rate %d is "
604 			    "less than minimum %d\n", rate, KIOCRPTRATE_MIN);
605 		else
606 			perror("kbd: set repeat rate");
607 		return (1);
608 	}
609 
610 	return (0);
611 }
612 
613 #define	BAD_DEFAULT	"kbd: bad default value for %s: %s\n"
614 
615 static void
616 kbd_defaults(int kbd)
617 {
618 	char *p, *endptr;
619 	int layout_num, freq;
620 
621 	if (defopen(DEF_FILE) != 0) {
622 		(void) fprintf(stderr, "Can't open default file: %s\n",
623 		    DEF_FILE);
624 		exit(1);
625 	}
626 
627 	p = defread(DEF_CLICK);
628 	if (p != NULL) {
629 		/*
630 		 * KEYCLICK must equal "on" or "off"
631 		 */
632 		if ((strcmp(p, "on") == 0) || (strcmp(p, "off") == 0))
633 			(void) click(p, kbd);
634 		else
635 			(void) fprintf(stderr, BAD_DEFAULT, DEF_CLICK, p);
636 	}
637 
638 	p = defread(DEF_ABORT);
639 	if (p != NULL) {
640 		/*
641 		 * ABORT must equal "enable", "disable" or "alternate"
642 		 */
643 		if ((strcmp(p, "enable") == 0) ||
644 		    (strcmp(p, "alternate") == 0) ||
645 		    (strcmp(p, "disable") == 0))
646 			(void) abort_enable(p, kbd);
647 		else
648 			(void) fprintf(stderr, BAD_DEFAULT, DEF_ABORT, p);
649 	}
650 
651 	p = defread(DEF_RPTDELAY);
652 	if (p != NULL) {
653 		/*
654 		 * REPEAT_DELAY unit in ms
655 		 */
656 		if (atoi(p) > 0)
657 			(void) set_repeat_delay(p, kbd);
658 		else
659 			(void) fprintf(stderr, BAD_DEFAULT, DEF_RPTDELAY, p);
660 	}
661 
662 	p = defread(DEF_RPTRATE);
663 	if (p != NULL) {
664 		/*
665 		 * REPEAT_RATE unit in ms
666 		 */
667 		if (atoi(p) > 0)
668 			(void) set_repeat_rate(p, kbd);
669 		else
670 			(void) fprintf(stderr, BAD_DEFAULT, DEF_RPTRATE, p);
671 	}
672 
673 	p = defread(DEF_LAYOUT);
674 	if (p != NULL) {
675 		/*
676 		 * LAYOUT must be one of the layouts supported in kbd_layouts
677 		 */
678 		if (get_layouts() != 0)
679 			return;
680 
681 		if ((layout_num = get_layout_number(p)) == -1) {
682 			(void) fprintf(stderr, BAD_DEFAULT, DEF_LAYOUT, p);
683 			return;
684 		}
685 
686 		(void) set_layout(kbd, layout_num);
687 	}
688 
689 	p = defread(DEF_KBDFREQ);
690 	if (p != NULL) {
691 		/*
692 		 * Keyboard beeper frequency unit in Hz
693 		 */
694 		endptr = NULL;
695 		errno = 0;
696 		freq = (int)strtol(p, &endptr, 10);
697 		if (errno == 0 && endptr[0] == '\0' &&
698 		    freq >= 0 && freq <= INT16_MAX)
699 			(void) set_beep_freq(kbd, "keyboard", freq);
700 		else
701 			(void) fprintf(stderr, BAD_DEFAULT, DEF_KBDFREQ, p);
702 	}
703 
704 	p = defread(DEF_CONSFREQ);
705 	if (p != NULL) {
706 		/*
707 		 * Console beeper frequency unit in Hz
708 		 */
709 		endptr = NULL;
710 		errno = 0;
711 		freq = (int)strtol(p, &endptr, 10);
712 		if (errno == 0 && endptr[0] == '\0' &&
713 		    freq >= 0 && freq <= INT16_MAX)
714 			(void) set_beep_freq(kbd, "console", freq);
715 		else
716 			(void) fprintf(stderr, BAD_DEFAULT, DEF_CONSFREQ, p);
717 	}
718 }
719 
720 static int
721 get_layout_number(char *layout)
722 {
723 	int i;
724 	int layout_number = -1;
725 
726 	for (i = 0; i < layout_count; i ++) {
727 		if (strcmp(layout, layout_names[i]) == 0) {
728 			layout_number = layout_numbers[i];
729 			break;
730 		}
731 	}
732 
733 	return (layout_number);
734 }
735 
736 static int
737 get_layouts()
738 {
739 	FILE *stream;
740 	char buffer[MAX_LINE_SIZE];
741 	char *result = NULL;
742 	int  i = 0;
743 	char *tmpbuf;
744 
745 	if ((stream = fopen(KBD_LAYOUT_FILE, "r")) == 0) {
746 		perror(KBD_LAYOUT_FILE);
747 		return (1);
748 	}
749 
750 	while ((fgets(buffer, MAX_LINE_SIZE, stream) != NULL) &&
751 	    (i < MAX_LAYOUT_NUM)) {
752 		if (buffer[0] == '#')
753 			continue;
754 		if ((result = strtok(buffer, "=")) == NULL)
755 			continue;
756 		if ((tmpbuf = strdup(result)) != NULL) {
757 			layout_names[i] = tmpbuf;
758 		} else {
759 			perror("out of memory getting layout names");
760 			return (1);
761 		}
762 		if ((result = strtok(NULL, "\n")) == NULL)
763 			continue;
764 		layout_numbers[i] = atoi(result);
765 		if (strcmp(tmpbuf, "US-English") == 0)
766 			default_layout_number = i;
767 		i++;
768 	}
769 	layout_count = i;
770 
771 	return (0);
772 }
773 
774 /*
775  * this routine sets the layout of the keyboard being used
776  */
777 static int
778 set_layout(int kbd, int layout_num)
779 {
780 
781 	if (ioctl(kbd, KIOCSLAYOUT, layout_num)) {
782 		perror("ioctl (set kbd layout)");
783 		return (1);
784 	}
785 
786 	return (0);
787 }
788 
789 static char *usage1 = "kbd [-r] [-t] [-l] [-a enable|disable|alternate]";
790 static char *usage2 = "    [-c on|off][-D delay][-R rate][-d keyboard device]";
791 static char *usage3 = "kbd -i [-d keyboard device]";
792 static char *usage4 = "kbd -s [language]";
793 static char *usage5 = "kbd -b [keyboard|console] frequency";
794 
795 static void
796 usage(void)
797 {
798 	(void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", usage1,
799 	    usage2, usage3, usage4, usage5);
800 }
801