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