xref: /titanic_54/usr/src/cmd/kbd/kbd.c (revision 7db6e34e0974b29ab599ed5dbc95a2f71810f321)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*7db6e34eSqz150045  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  *	Usage: kbd [-r] [-t] [-l] [-i] [-c on|off] [-a enable|disable|alternate]
327c478bd9Sstevel@tonic-gate  *		    [-d keyboard device]
337c478bd9Sstevel@tonic-gate  *	-r			reset the keyboard as if power-up
347c478bd9Sstevel@tonic-gate  *	-t			return the type of the keyboard being used
357c478bd9Sstevel@tonic-gate  *	-l			return the layout of the keyboard being used,
367c478bd9Sstevel@tonic-gate  *				and the Autorepeat settings
377c478bd9Sstevel@tonic-gate  *	-i			read in the default configuration file
387c478bd9Sstevel@tonic-gate  *	-c on|off		turn on|off clicking
397c478bd9Sstevel@tonic-gate  *	-a enable|disable|alternate	sets abort sequence
407c478bd9Sstevel@tonic-gate  *	-D autorepeat delay	sets autorepeat dealy, unit in ms
417c478bd9Sstevel@tonic-gate  *	-R autorepeat rate	sets autorepeat rate, unit in ms
427c478bd9Sstevel@tonic-gate  *	-d keyboard device	chooses the kbd device, default /dev/kbd.
43*7db6e34eSqz150045  *	-s keyboard layout	sets keyboard layout
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
487c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
497c478bd9Sstevel@tonic-gate #include <sys/kbd.h>
507c478bd9Sstevel@tonic-gate #include <stdio.h>
517c478bd9Sstevel@tonic-gate #include <fcntl.h>
527c478bd9Sstevel@tonic-gate #include <deflt.h>
537c478bd9Sstevel@tonic-gate #include <unistd.h>
547c478bd9Sstevel@tonic-gate #include <string.h>
557c478bd9Sstevel@tonic-gate #include <stdlib.h>
567c478bd9Sstevel@tonic-gate #include <stropts.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	KBD_DEVICE	"/dev/kbd"		/* default keyboard device */
597c478bd9Sstevel@tonic-gate #define	DEF_FILE	"/etc/default/kbd"	/* kbd defaults file	*/
607c478bd9Sstevel@tonic-gate #define	DEF_ABORT	"KEYBOARD_ABORT="
617c478bd9Sstevel@tonic-gate #define	DEF_CLICK	"KEYCLICK="
627c478bd9Sstevel@tonic-gate #define	DEF_RPTDELAY	"REPEAT_DELAY="
637c478bd9Sstevel@tonic-gate #define	DEF_RPTRATE	"REPEAT_RATE="
64*7db6e34eSqz150045 #define	DEF_LAYOUT	"LAYOUT="
65*7db6e34eSqz150045 
66*7db6e34eSqz150045 #define	KBD_LAYOUT_FILE  "/usr/share/lib/keytables/type_6/kbd_layouts"
67*7db6e34eSqz150045 #define	MAX_LAYOUT_NUM		128
68*7db6e34eSqz150045 #define	MAX_LINE_SIZE		256
69*7db6e34eSqz150045 #define	DEFAULT_KBD_LAYOUT	33
70*7db6e34eSqz150045 
71*7db6e34eSqz150045 char *layout_names[MAX_LAYOUT_NUM];
72*7db6e34eSqz150045 int layout_numbers[MAX_LAYOUT_NUM];
73*7db6e34eSqz150045 static int layout_count;
74*7db6e34eSqz150045 static int default_layout_number = 0;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static void reset(int);
777c478bd9Sstevel@tonic-gate static void get_type(int);
787c478bd9Sstevel@tonic-gate static void get_layout(int);
797c478bd9Sstevel@tonic-gate static void kbd_defaults(int);
807c478bd9Sstevel@tonic-gate static void usage(void);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static int click(char *, int);
837c478bd9Sstevel@tonic-gate static int abort_enable(char *, int);
847c478bd9Sstevel@tonic-gate static int set_repeat_delay(char *, int);
857c478bd9Sstevel@tonic-gate static int set_repeat_rate(char *, int);
867c478bd9Sstevel@tonic-gate 
87*7db6e34eSqz150045 static int get_layout_number(char *);
88*7db6e34eSqz150045 static int set_layout(int, int);
89*7db6e34eSqz150045 static int get_layouts(void);
90*7db6e34eSqz150045 static int set_kbd_layout(int, char *);
91*7db6e34eSqz150045 
927c478bd9Sstevel@tonic-gate int
937c478bd9Sstevel@tonic-gate main(int argc, char **argv)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate 	int c, error;
967c478bd9Sstevel@tonic-gate 	int rflag, tflag, lflag, cflag, dflag, aflag, iflag, errflag,
97*7db6e34eSqz150045 	    Dflag, Rflag, rtlacDRflag, sflag;
98*7db6e34eSqz150045 	char *copt, *aopt, *delay, *rate, *layout_name;
997c478bd9Sstevel@tonic-gate 	char *kbdname = KBD_DEVICE;
1007c478bd9Sstevel@tonic-gate 	int kbd;
1017c478bd9Sstevel@tonic-gate 	extern char *optarg;
1027c478bd9Sstevel@tonic-gate 	extern int optind;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag =
105*7db6e34eSqz150045 	    Dflag = Rflag = sflag = 0;
1067c478bd9Sstevel@tonic-gate 	copt = aopt = (char *)0;
1077c478bd9Sstevel@tonic-gate 
108*7db6e34eSqz150045 	while ((c = getopt(argc, argv, "rtlisc:a:d:D:R:")) != EOF) {
1097c478bd9Sstevel@tonic-gate 		switch (c) {
1107c478bd9Sstevel@tonic-gate 		case 'r':
1117c478bd9Sstevel@tonic-gate 			rflag++;
1127c478bd9Sstevel@tonic-gate 			break;
1137c478bd9Sstevel@tonic-gate 		case 't':
1147c478bd9Sstevel@tonic-gate 			tflag++;
1157c478bd9Sstevel@tonic-gate 			break;
1167c478bd9Sstevel@tonic-gate 		case 'l':
1177c478bd9Sstevel@tonic-gate 			lflag++;
1187c478bd9Sstevel@tonic-gate 			break;
1197c478bd9Sstevel@tonic-gate 		case 'i':
1207c478bd9Sstevel@tonic-gate 			iflag++;
1217c478bd9Sstevel@tonic-gate 			break;
122*7db6e34eSqz150045 		case 's':
123*7db6e34eSqz150045 			sflag++;
124*7db6e34eSqz150045 			break;
1257c478bd9Sstevel@tonic-gate 		case 'c':
1267c478bd9Sstevel@tonic-gate 			copt = optarg;
1277c478bd9Sstevel@tonic-gate 			cflag++;
1287c478bd9Sstevel@tonic-gate 			break;
1297c478bd9Sstevel@tonic-gate 		case 'a':
1307c478bd9Sstevel@tonic-gate 			aopt = optarg;
1317c478bd9Sstevel@tonic-gate 			aflag++;
1327c478bd9Sstevel@tonic-gate 			break;
1337c478bd9Sstevel@tonic-gate 		case 'd':
1347c478bd9Sstevel@tonic-gate 			kbdname = optarg;
1357c478bd9Sstevel@tonic-gate 			dflag++;
1367c478bd9Sstevel@tonic-gate 			break;
1377c478bd9Sstevel@tonic-gate 		case 'D':
1387c478bd9Sstevel@tonic-gate 			delay = optarg;
1397c478bd9Sstevel@tonic-gate 			Dflag++;
1407c478bd9Sstevel@tonic-gate 			break;
1417c478bd9Sstevel@tonic-gate 		case 'R':
1427c478bd9Sstevel@tonic-gate 			rate = optarg;
1437c478bd9Sstevel@tonic-gate 			Rflag++;
1447c478bd9Sstevel@tonic-gate 			break;
1457c478bd9Sstevel@tonic-gate 		case '?':
1467c478bd9Sstevel@tonic-gate 			errflag++;
1477c478bd9Sstevel@tonic-gate 			break;
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/*
1527c478bd9Sstevel@tonic-gate 	 * Check for valid arguments:
1537c478bd9Sstevel@tonic-gate 	 *
1547c478bd9Sstevel@tonic-gate 	 * If argument parsing failed or if there are left-over
155*7db6e34eSqz150045 	 * command line arguments(except -s option), then we're done now.
1567c478bd9Sstevel@tonic-gate 	 */
157*7db6e34eSqz150045 	if (errflag != 0 || ((sflag == 0) && (argc != optind))) {
1587c478bd9Sstevel@tonic-gate 		usage();
1597c478bd9Sstevel@tonic-gate 		exit(1);
1607c478bd9Sstevel@tonic-gate 	}
161*7db6e34eSqz150045 
1627c478bd9Sstevel@tonic-gate 	/*
163*7db6e34eSqz150045 	 * kbd requires that the user specify either "-i" or "-s" or at
164*7db6e34eSqz150045 	 * least one of -[rtlacDR].  The "-d" option is, well, optional.
165*7db6e34eSqz150045 	 * We don't care if it's there or not.
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	rtlacDRflag = rflag + tflag + lflag + aflag + cflag + Dflag + Rflag;
168*7db6e34eSqz150045 	if (!((iflag != 0 && sflag == 0 && rtlacDRflag == 0) ||
169*7db6e34eSqz150045 	    (iflag == 0 && sflag != 0 && dflag == 0 && rtlacDRflag == 0) ||
170*7db6e34eSqz150045 	    (iflag == 0 && sflag == 0 && rtlacDRflag != 0))) {
1717c478bd9Sstevel@tonic-gate 		usage();
1727c478bd9Sstevel@tonic-gate 		exit(1);
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (Dflag && atoi(delay) <= 0) {
1767c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Invalid arguments: -D %s\n", delay);
1777c478bd9Sstevel@tonic-gate 		usage();
1787c478bd9Sstevel@tonic-gate 		exit(1);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (Rflag && atoi(rate) <= 0) {
1827c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Invalid arguments: -R %s\n", rate);
1837c478bd9Sstevel@tonic-gate 		usage();
1847c478bd9Sstevel@tonic-gate 		exit(1);
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/*
1887c478bd9Sstevel@tonic-gate 	 * Open the keyboard device
1897c478bd9Sstevel@tonic-gate 	 */
1907c478bd9Sstevel@tonic-gate 	if ((kbd = open(kbdname, O_RDWR)) < 0) {
1917c478bd9Sstevel@tonic-gate 		perror("opening the keyboard");
1927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "kbd: Cannot open %s\n", kbdname);
1937c478bd9Sstevel@tonic-gate 		exit(1);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	if (iflag) {
1977c478bd9Sstevel@tonic-gate 		kbd_defaults(kbd);
1987c478bd9Sstevel@tonic-gate 		exit(0);	/* A mutually exclusive option */
1997c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	if (tflag)
2037c478bd9Sstevel@tonic-gate 		get_type(kbd);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (lflag)
2067c478bd9Sstevel@tonic-gate 		get_layout(kbd);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if (cflag && (error = click(copt, kbd)) != 0)
2097c478bd9Sstevel@tonic-gate 		exit(error);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if (rflag)
2127c478bd9Sstevel@tonic-gate 		reset(kbd);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	if (aflag && (error = abort_enable(aopt, kbd)) != 0)
2157c478bd9Sstevel@tonic-gate 		exit(error);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	if (Dflag && (error = set_repeat_delay(delay, kbd)) != 0)
2187c478bd9Sstevel@tonic-gate 		exit(error);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0)
2217c478bd9Sstevel@tonic-gate 		exit(error);
2227c478bd9Sstevel@tonic-gate 
223*7db6e34eSqz150045 	if (sflag) {
224*7db6e34eSqz150045 		if (argc == optind) {
225*7db6e34eSqz150045 			layout_name = NULL;
226*7db6e34eSqz150045 		} else if (argc == (optind + 1)) {
227*7db6e34eSqz150045 			layout_name = argv[optind];
228*7db6e34eSqz150045 		} else {
229*7db6e34eSqz150045 			usage();
230*7db6e34eSqz150045 			exit(1);
231*7db6e34eSqz150045 		}
232*7db6e34eSqz150045 
233*7db6e34eSqz150045 		if ((error = set_kbd_layout(kbd, layout_name)) != 0)
234*7db6e34eSqz150045 			exit(error);
235*7db6e34eSqz150045 	}
236*7db6e34eSqz150045 
237*7db6e34eSqz150045 	return (0);
238*7db6e34eSqz150045 }
239*7db6e34eSqz150045 
240*7db6e34eSqz150045 /*
241*7db6e34eSqz150045  * this routine gets the type of the keyboard being used
242*7db6e34eSqz150045  */
243*7db6e34eSqz150045 static int
244*7db6e34eSqz150045 set_kbd_layout(int kbd, char *layout_name)
245*7db6e34eSqz150045 {
246*7db6e34eSqz150045 	int layout_num;
247*7db6e34eSqz150045 	int error = 1;
248*7db6e34eSqz150045 
249*7db6e34eSqz150045 	/* get the language info from the layouts file */
250*7db6e34eSqz150045 	if (get_layouts() != 0)
251*7db6e34eSqz150045 		return (error);
252*7db6e34eSqz150045 
253*7db6e34eSqz150045 	if (layout_name != NULL) {
254*7db6e34eSqz150045 		if ((layout_num = get_layout_number(layout_name)) == -1) {
255*7db6e34eSqz150045 			(void) fprintf(stderr, "%s: unknown layout name\n"
256*7db6e34eSqz150045 				    "Please refer to 'kbd -s' to get the "
257*7db6e34eSqz150045 				    "supported layouts.\n", layout_name);
258*7db6e34eSqz150045 			return (error);
259*7db6e34eSqz150045 		}
260*7db6e34eSqz150045 	} else {
261*7db6e34eSqz150045 			int i, j, print_cnt, input_num;
262*7db6e34eSqz150045 			boolean_t input_right = B_TRUE;
263*7db6e34eSqz150045 			boolean_t default_input = B_FALSE;
264*7db6e34eSqz150045 			char input[8]; /* 8 chars is enough for numbers */
265*7db6e34eSqz150045 
266*7db6e34eSqz150045 			print_cnt = (layout_count % 2) ?
267*7db6e34eSqz150045 				layout_count/2+1 : layout_count/2;
268*7db6e34eSqz150045 
269*7db6e34eSqz150045 			for (i = 1; i <= print_cnt; i++) {
270*7db6e34eSqz150045 				(void) printf("%2d. %-30s", i,
271*7db6e34eSqz150045 					    layout_names[i-1]);
272*7db6e34eSqz150045 				j = i + print_cnt;
273*7db6e34eSqz150045 				if (j <= layout_count) {
274*7db6e34eSqz150045 					(void) printf("%-2d. %-30s\n", j,
275*7db6e34eSqz150045 						    layout_names[j-1]);
276*7db6e34eSqz150045 				}
277*7db6e34eSqz150045 			}
278*7db6e34eSqz150045 			(void) printf("\nTo select the keyboard layout, enter"
279*7db6e34eSqz150045 				    " a number [default %d]:",
280*7db6e34eSqz150045 				    default_layout_number+1);
281*7db6e34eSqz150045 
282*7db6e34eSqz150045 			for (;;) {
283*7db6e34eSqz150045 				if (input_right == B_FALSE)
284*7db6e34eSqz150045 					(void) printf("Invalid input. Please "
285*7db6e34eSqz150045 					    "input a number (1,2,...):");
286*7db6e34eSqz150045 				(void) memset(input, 0, 8);
287*7db6e34eSqz150045 				(void) fflush(stdin);
288*7db6e34eSqz150045 				(void) fgets(input, 8, stdin);
289*7db6e34eSqz150045 				if (strlen(input) > 4) {
290*7db6e34eSqz150045 					input_right = B_FALSE;
291*7db6e34eSqz150045 					continue;
292*7db6e34eSqz150045 				}
293*7db6e34eSqz150045 				if (input[0] == '\n') {
294*7db6e34eSqz150045 					default_input = B_TRUE;
295*7db6e34eSqz150045 					break;
296*7db6e34eSqz150045 				}
297*7db6e34eSqz150045 				input_right = B_TRUE;
298*7db6e34eSqz150045 				/* check if the inputs are numbers 0~9 */
299*7db6e34eSqz150045 				for (i = 0; i < (strlen(input) - 1); i++) {
300*7db6e34eSqz150045 					if ((input[i] < '0') ||
301*7db6e34eSqz150045 					    (input[i] > '9')) {
302*7db6e34eSqz150045 						input_right = B_FALSE;
303*7db6e34eSqz150045 						break;
304*7db6e34eSqz150045 					}
305*7db6e34eSqz150045 				}
306*7db6e34eSqz150045 				if (input_right == B_FALSE)
307*7db6e34eSqz150045 					continue;
308*7db6e34eSqz150045 				input_num = atoi(input);
309*7db6e34eSqz150045 				if ((input_num > 0) &&
310*7db6e34eSqz150045 				    (input_num <= layout_count))
311*7db6e34eSqz150045 					break;
312*7db6e34eSqz150045 				else
313*7db6e34eSqz150045 					input_right = B_FALSE;
314*7db6e34eSqz150045 			}
315*7db6e34eSqz150045 			if (default_input == B_TRUE)
316*7db6e34eSqz150045 				layout_num = DEFAULT_KBD_LAYOUT;
317*7db6e34eSqz150045 			else
318*7db6e34eSqz150045 				layout_num = layout_numbers[--input_num];
319*7db6e34eSqz150045 	}
320*7db6e34eSqz150045 
321*7db6e34eSqz150045 	if ((error = set_layout(kbd, layout_num)) != 0)
322*7db6e34eSqz150045 		return (error);
323*7db6e34eSqz150045 
3247c478bd9Sstevel@tonic-gate 	return (0);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate  * this routine resets the state of the keyboard as if power-up
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate static void
3317c478bd9Sstevel@tonic-gate reset(int kbd)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	int cmd;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	cmd = KBD_CMD_RESET;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCCMD, &cmd)) {
3387c478bd9Sstevel@tonic-gate 		perror("kbd: ioctl error");
3397c478bd9Sstevel@tonic-gate 		exit(1);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate  * this routine gets the type of the keyboard being used
3467c478bd9Sstevel@tonic-gate  */
3477c478bd9Sstevel@tonic-gate static void
3487c478bd9Sstevel@tonic-gate get_type(int kbd)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate 	int kbd_type;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
3537c478bd9Sstevel@tonic-gate 		perror("ioctl (kbd type)");
3547c478bd9Sstevel@tonic-gate 		exit(1);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	switch (kbd_type) {
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	case KB_SUN3:
3607c478bd9Sstevel@tonic-gate 		(void) printf("Type 3 Sun keyboard\n");
3617c478bd9Sstevel@tonic-gate 		break;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	case KB_SUN4:
3647c478bd9Sstevel@tonic-gate 		(void) printf("Type 4 Sun keyboard\n");
3657c478bd9Sstevel@tonic-gate 		break;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	case KB_ASCII:
3687c478bd9Sstevel@tonic-gate 		(void) printf("ASCII\n");
3697c478bd9Sstevel@tonic-gate 		break;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	case KB_PC:
3727c478bd9Sstevel@tonic-gate 		(void) printf("PC\n");
3737c478bd9Sstevel@tonic-gate 		break;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	case KB_USB:
3767c478bd9Sstevel@tonic-gate 		(void) printf("USB keyboard\n");
3777c478bd9Sstevel@tonic-gate 		break;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	default:
3807c478bd9Sstevel@tonic-gate 		(void) printf("Unknown keyboard type\n");
3817c478bd9Sstevel@tonic-gate 		break;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * this routine gets the layout of the keyboard being used
3877c478bd9Sstevel@tonic-gate  * also, included the autorepeat delay and rate being used
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate static void
3907c478bd9Sstevel@tonic-gate get_layout(int kbd)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	int kbd_type;
3937c478bd9Sstevel@tonic-gate 	int kbd_layout;
3947c478bd9Sstevel@tonic-gate 	/* these two variables are used for getting delay&rate */
3957c478bd9Sstevel@tonic-gate 	int delay, rate;
3967c478bd9Sstevel@tonic-gate 	delay = rate = 0;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
3997c478bd9Sstevel@tonic-gate 		perror("ioctl (kbd type)");
4007c478bd9Sstevel@tonic-gate 		exit(1);
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCLAYOUT, &kbd_layout)) {
4047c478bd9Sstevel@tonic-gate 		perror("ioctl (kbd layout)");
4057c478bd9Sstevel@tonic-gate 		exit(1);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	(void) printf("type=%d\nlayout=%d (0x%.2x)\n",
4097c478bd9Sstevel@tonic-gate 	    kbd_type, kbd_layout, kbd_layout);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/* below code is used to get the autorepeat delay and rate */
4127c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCGRPTDELAY, &delay)) {
4137c478bd9Sstevel@tonic-gate 		perror("ioctl (kbd get repeat delay)");
4147c478bd9Sstevel@tonic-gate 		exit(1);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCGRPTRATE, &rate)) {
4187c478bd9Sstevel@tonic-gate 		perror("ioctl (kbd get repeat rate)");
4197c478bd9Sstevel@tonic-gate 		exit(1);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	(void) printf("delay(ms)=%d\n", delay);
4237c478bd9Sstevel@tonic-gate 	(void) printf("rate(ms)=%d\n", rate);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate  * this routine enables or disables clicking of the keyboard
4287c478bd9Sstevel@tonic-gate  */
4297c478bd9Sstevel@tonic-gate static int
4307c478bd9Sstevel@tonic-gate click(char *copt, int kbd)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	int cmd;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	if (strcmp(copt, "on") == 0)
4357c478bd9Sstevel@tonic-gate 		cmd = KBD_CMD_CLICK;
4367c478bd9Sstevel@tonic-gate 	else if (strcmp(copt, "off") == 0)
4377c478bd9Sstevel@tonic-gate 		cmd = KBD_CMD_NOCLICK;
4387c478bd9Sstevel@tonic-gate 	else {
4397c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "wrong option -- %s\n", copt);
4407c478bd9Sstevel@tonic-gate 		usage();
4417c478bd9Sstevel@tonic-gate 		return (1);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCCMD, &cmd)) {
4457c478bd9Sstevel@tonic-gate 		perror("kbd ioctl (keyclick)");
4467c478bd9Sstevel@tonic-gate 		return (1);
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	return (0);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate  * this routine enables/disables/sets BRK or abort sequence feature
4537c478bd9Sstevel@tonic-gate  */
4547c478bd9Sstevel@tonic-gate static int
4557c478bd9Sstevel@tonic-gate abort_enable(char *aopt, int kbd)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 	int enable;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (strcmp(aopt, "alternate") == 0)
4607c478bd9Sstevel@tonic-gate 		enable = KIOCABORTALTERNATE;
4617c478bd9Sstevel@tonic-gate 	else if (strcmp(aopt, "enable") == 0)
4627c478bd9Sstevel@tonic-gate 		enable = KIOCABORTENABLE;
4637c478bd9Sstevel@tonic-gate 	else if (strcmp(aopt, "disable") == 0)
4647c478bd9Sstevel@tonic-gate 		enable = KIOCABORTDISABLE;
4657c478bd9Sstevel@tonic-gate 	else {
4667c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "wrong option -- %s\n", aopt);
4677c478bd9Sstevel@tonic-gate 		usage();
4687c478bd9Sstevel@tonic-gate 		return (1);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCSKABORTEN, &enable)) {
4727c478bd9Sstevel@tonic-gate 		perror("kbd ioctl (abort enable)");
4737c478bd9Sstevel@tonic-gate 		return (1);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	return (0);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * this routine set autorepeat delay
4807c478bd9Sstevel@tonic-gate  */
4817c478bd9Sstevel@tonic-gate static int
4827c478bd9Sstevel@tonic-gate set_repeat_delay(char *delay_str, int kbd)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	int delay = atoi(delay_str);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * The error message depends on the different inputs.
4887c478bd9Sstevel@tonic-gate 	 * a. the input is a invalid integer(unit in ms)
4897c478bd9Sstevel@tonic-gate 	 * b. the input is a integer less than the minimal delay setting.
4907c478bd9Sstevel@tonic-gate 	 * The condition (a) has been covered by main function and set_default
4917c478bd9Sstevel@tonic-gate 	 * function.
4927c478bd9Sstevel@tonic-gate 	 */
4937c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCSRPTDELAY, &delay) == -1) {
4947c478bd9Sstevel@tonic-gate 		if (delay < KIOCRPTDELAY_MIN)
4957c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "kbd: specified delay %d is "
4967c478bd9Sstevel@tonic-gate 			    "less than minimum %d\n", delay, KIOCRPTDELAY_MIN);
4977c478bd9Sstevel@tonic-gate 		else
4987c478bd9Sstevel@tonic-gate 			perror("kbd: set repeat delay");
4997c478bd9Sstevel@tonic-gate 		return (1);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	return (0);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate  * this routine set autorepeat rate
5077c478bd9Sstevel@tonic-gate  */
5087c478bd9Sstevel@tonic-gate static int
5097c478bd9Sstevel@tonic-gate set_repeat_rate(char *rate_str, int kbd)
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	int rate = atoi(rate_str);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/*
5147c478bd9Sstevel@tonic-gate 	 * The error message depends on the different inputs.
5157c478bd9Sstevel@tonic-gate 	 * a. the input is a invalid integer(unit in ms)
5167c478bd9Sstevel@tonic-gate 	 * b. the input is a integer less than the minimal rate setting.
5177c478bd9Sstevel@tonic-gate 	 * The condition (a) has been covered by main function and set_default
5187c478bd9Sstevel@tonic-gate 	 * function.
5197c478bd9Sstevel@tonic-gate 	 */
5207c478bd9Sstevel@tonic-gate 	if (ioctl(kbd, KIOCSRPTRATE, &rate) == -1) {
5217c478bd9Sstevel@tonic-gate 		if (rate < KIOCRPTRATE_MIN)
5227c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "kbd: specified rate %d is "
5237c478bd9Sstevel@tonic-gate 			    "less than minimum %d\n", rate, KIOCRPTRATE_MIN);
5247c478bd9Sstevel@tonic-gate 		else
5257c478bd9Sstevel@tonic-gate 			perror("kbd: set repeat rate");
5267c478bd9Sstevel@tonic-gate 		return (1);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	return (0);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate #define	BAD_DEFAULT	"kbd: bad default value for %s: %s\n"
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate static void
5357c478bd9Sstevel@tonic-gate kbd_defaults(int kbd)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	char *p;
538*7db6e34eSqz150045 	int layout_num;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if (defopen(DEF_FILE) != 0) {
5417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Can't open default file: %s\n",
5427c478bd9Sstevel@tonic-gate 		    DEF_FILE);
5437c478bd9Sstevel@tonic-gate 		exit(1);
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	p = defread(DEF_CLICK);
5477c478bd9Sstevel@tonic-gate 	if (p != NULL) {
5487c478bd9Sstevel@tonic-gate 		/*
5497c478bd9Sstevel@tonic-gate 		 * KEYCLICK must equal "on" or "off"
5507c478bd9Sstevel@tonic-gate 		 */
5517c478bd9Sstevel@tonic-gate 		if ((strcmp(p, "on") == 0) || (strcmp(p, "off") == 0))
5527c478bd9Sstevel@tonic-gate 			(void) click(p, kbd);
5537c478bd9Sstevel@tonic-gate 		else
5547c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, BAD_DEFAULT, DEF_CLICK, p);
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	p = defread(DEF_ABORT);
5587c478bd9Sstevel@tonic-gate 	if (p != NULL) {
5597c478bd9Sstevel@tonic-gate 		/*
5607c478bd9Sstevel@tonic-gate 		 * ABORT must equal "enable", "disable" or "alternate"
5617c478bd9Sstevel@tonic-gate 		 */
5627c478bd9Sstevel@tonic-gate 		if ((strcmp(p, "enable") == 0) ||
5637c478bd9Sstevel@tonic-gate 		    (strcmp(p, "alternate") == 0) ||
5647c478bd9Sstevel@tonic-gate 		    (strcmp(p, "disable") == 0))
5657c478bd9Sstevel@tonic-gate 			(void) abort_enable(p, kbd);
5667c478bd9Sstevel@tonic-gate 		else
5677c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, BAD_DEFAULT, DEF_ABORT, p);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	p = defread(DEF_RPTDELAY);
5717c478bd9Sstevel@tonic-gate 	if (p != NULL) {
5727c478bd9Sstevel@tonic-gate 		/*
5737c478bd9Sstevel@tonic-gate 		 * REPEAT_DELAY unit in ms
5747c478bd9Sstevel@tonic-gate 		 */
5757c478bd9Sstevel@tonic-gate 		if (atoi(p) > 0)
5767c478bd9Sstevel@tonic-gate 			(void) set_repeat_delay(p, kbd);
5777c478bd9Sstevel@tonic-gate 		else
5787c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, BAD_DEFAULT, DEF_RPTDELAY, p);
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	p = defread(DEF_RPTRATE);
5827c478bd9Sstevel@tonic-gate 	if (p != NULL) {
5837c478bd9Sstevel@tonic-gate 		/*
5847c478bd9Sstevel@tonic-gate 		 * REPEAT_RATE unit in ms
5857c478bd9Sstevel@tonic-gate 		 */
5867c478bd9Sstevel@tonic-gate 		if (atoi(p) > 0)
5877c478bd9Sstevel@tonic-gate 			(void) set_repeat_rate(p, kbd);
5887c478bd9Sstevel@tonic-gate 		else
5897c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, BAD_DEFAULT, DEF_RPTRATE, p);
5907c478bd9Sstevel@tonic-gate 	}
591*7db6e34eSqz150045 
592*7db6e34eSqz150045 	p = defread(DEF_LAYOUT);
593*7db6e34eSqz150045 	if (p != NULL) {
594*7db6e34eSqz150045 		/*
595*7db6e34eSqz150045 		 * LAYOUT must be one of the layouts supported in kbd_layouts
596*7db6e34eSqz150045 		 */
597*7db6e34eSqz150045 		if (get_layouts() != 0)
598*7db6e34eSqz150045 			return;
599*7db6e34eSqz150045 
600*7db6e34eSqz150045 		if ((layout_num = get_layout_number(p)) == -1) {
601*7db6e34eSqz150045 			(void) fprintf(stderr, BAD_DEFAULT, DEF_LAYOUT, p);
602*7db6e34eSqz150045 			return;
603*7db6e34eSqz150045 		}
604*7db6e34eSqz150045 
605*7db6e34eSqz150045 		(void) set_layout(kbd, layout_num);
606*7db6e34eSqz150045 	}
607*7db6e34eSqz150045 }
608*7db6e34eSqz150045 
609*7db6e34eSqz150045 static int
610*7db6e34eSqz150045 get_layout_number(char *layout)
611*7db6e34eSqz150045 {
612*7db6e34eSqz150045 	int i;
613*7db6e34eSqz150045 	int layout_number = -1;
614*7db6e34eSqz150045 
615*7db6e34eSqz150045 	for (i = 0; i < layout_count; i ++) {
616*7db6e34eSqz150045 		if (strcmp(layout, layout_names[i]) == 0) {
617*7db6e34eSqz150045 			layout_number = layout_numbers[i];
618*7db6e34eSqz150045 			break;
619*7db6e34eSqz150045 		}
620*7db6e34eSqz150045 	}
621*7db6e34eSqz150045 
622*7db6e34eSqz150045 	return (layout_number);
623*7db6e34eSqz150045 }
624*7db6e34eSqz150045 
625*7db6e34eSqz150045 static int
626*7db6e34eSqz150045 get_layouts()
627*7db6e34eSqz150045 {
628*7db6e34eSqz150045 	FILE *stream;
629*7db6e34eSqz150045 	char buffer[MAX_LINE_SIZE];
630*7db6e34eSqz150045 	char *result = NULL;
631*7db6e34eSqz150045 	int  i = 0;
632*7db6e34eSqz150045 	char *tmpbuf;
633*7db6e34eSqz150045 
634*7db6e34eSqz150045 	if ((stream = fopen(KBD_LAYOUT_FILE, "r")) == 0) {
635*7db6e34eSqz150045 		perror(KBD_LAYOUT_FILE);
636*7db6e34eSqz150045 		return (1);
637*7db6e34eSqz150045 	}
638*7db6e34eSqz150045 
639*7db6e34eSqz150045 	while ((fgets(buffer, MAX_LINE_SIZE, stream) != NULL) &&
640*7db6e34eSqz150045 	    (i < MAX_LAYOUT_NUM)) {
641*7db6e34eSqz150045 		if (buffer[0] == '#')
642*7db6e34eSqz150045 			continue;
643*7db6e34eSqz150045 		if ((result = strtok(buffer, "=")) == NULL)
644*7db6e34eSqz150045 			continue;
645*7db6e34eSqz150045 		if ((tmpbuf = strdup(result)) != NULL) {
646*7db6e34eSqz150045 			layout_names[i] = tmpbuf;
647*7db6e34eSqz150045 		} else {
648*7db6e34eSqz150045 			perror("out of memory getting layout names");
649*7db6e34eSqz150045 			return (1);
650*7db6e34eSqz150045 		}
651*7db6e34eSqz150045 		if ((result = strtok(NULL, "\n")) == NULL)
652*7db6e34eSqz150045 			continue;
653*7db6e34eSqz150045 		layout_numbers[i] = atoi(result);
654*7db6e34eSqz150045 		if (strcmp(tmpbuf, "US-English") == 0)
655*7db6e34eSqz150045 			default_layout_number = i;
656*7db6e34eSqz150045 		i++;
657*7db6e34eSqz150045 	}
658*7db6e34eSqz150045 	layout_count = i;
659*7db6e34eSqz150045 
660*7db6e34eSqz150045 	return (0);
661*7db6e34eSqz150045 }
662*7db6e34eSqz150045 
663*7db6e34eSqz150045 /*
664*7db6e34eSqz150045  * this routine sets the layout of the keyboard being used
665*7db6e34eSqz150045  */
666*7db6e34eSqz150045 static int
667*7db6e34eSqz150045 set_layout(int kbd, int layout_num)
668*7db6e34eSqz150045 {
669*7db6e34eSqz150045 
670*7db6e34eSqz150045 	if (ioctl(kbd, KIOCSLAYOUT, layout_num)) {
671*7db6e34eSqz150045 		perror("ioctl (set kbd layout)");
672*7db6e34eSqz150045 		return (1);
673*7db6e34eSqz150045 	}
674*7db6e34eSqz150045 
675*7db6e34eSqz150045 	return (0);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate static char *usage1 = "kbd [-r] [-t] [-l] [-a enable|disable|alternate]";
6797c478bd9Sstevel@tonic-gate static char *usage2 = "    [-c on|off][-D delay][-R rate][-d keyboard device]";
6807c478bd9Sstevel@tonic-gate static char *usage3 = "kbd -i [-d keyboard device]";
681*7db6e34eSqz150045 static char *usage4 = "kbd -s [language]";
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate static void
6847c478bd9Sstevel@tonic-gate usage(void)
6857c478bd9Sstevel@tonic-gate {
686*7db6e34eSqz150045 	(void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n\t%s\n", usage1, usage2,
687*7db6e34eSqz150045 	    usage3, usage4);
6887c478bd9Sstevel@tonic-gate }
689