xref: /illumos-gate/usr/src/cmd/kbd/kbd.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 
30 /*
31  *	Usage: kbd [-r] [-t] [-l] [-i] [-c on|off] [-a enable|disable|alternate]
32  *		    [-d keyboard device]
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  */
44 
45 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <sys/kbio.h>
48 #include <sys/kbd.h>
49 #include <stdio.h>
50 #include <fcntl.h>
51 #include <deflt.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <stropts.h>
56 
57 #define	KBD_DEVICE	"/dev/kbd"		/* default keyboard device */
58 #define	DEF_FILE	"/etc/default/kbd"	/* kbd defaults file	*/
59 #define	DEF_ABORT	"KEYBOARD_ABORT="
60 #define	DEF_CLICK	"KEYCLICK="
61 #define	DEF_RPTDELAY	"REPEAT_DELAY="
62 #define	DEF_RPTRATE	"REPEAT_RATE="
63 
64 static void reset(int);
65 static void get_type(int);
66 static void get_layout(int);
67 static void kbd_defaults(int);
68 static void usage(void);
69 
70 static int click(char *, int);
71 static int abort_enable(char *, int);
72 static int set_repeat_delay(char *, int);
73 static int set_repeat_rate(char *, int);
74 
75 int
76 main(int argc, char **argv)
77 {
78 	int c, error;
79 	int rflag, tflag, lflag, cflag, dflag, aflag, iflag, errflag,
80 	    Dflag, Rflag, rtlacDRflag;
81 	char *copt, *aopt, *delay, *rate;
82 	char *kbdname = KBD_DEVICE;
83 	int kbd;
84 	extern char *optarg;
85 	extern int optind;
86 
87 	rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag =
88 	    Dflag = Rflag = 0;
89 	copt = aopt = (char *)0;
90 
91 	while ((c = getopt(argc, argv, "rtlic:a:d:D:R:")) != EOF) {
92 		switch (c) {
93 		case 'r':
94 			rflag++;
95 			break;
96 		case 't':
97 			tflag++;
98 			break;
99 		case 'l':
100 			lflag++;
101 			break;
102 		case 'i':
103 			iflag++;
104 			break;
105 		case 'c':
106 			copt = optarg;
107 			cflag++;
108 			break;
109 		case 'a':
110 			aopt = optarg;
111 			aflag++;
112 			break;
113 		case 'd':
114 			kbdname = optarg;
115 			dflag++;
116 			break;
117 		case 'D':
118 			delay = optarg;
119 			Dflag++;
120 			break;
121 		case 'R':
122 			rate = optarg;
123 			Rflag++;
124 			break;
125 		case '?':
126 			errflag++;
127 			break;
128 		}
129 	}
130 
131 	/*
132 	 * Check for valid arguments:
133 	 *
134 	 * If argument parsing failed or if there are left-over
135 	 * command line arguments, then we're done now.
136 	 */
137 	if (errflag != 0 || argc != optind) {
138 		usage();
139 		exit(1);
140 	}
141 	/*
142 	 * kbd requires that the user specify either "-i" or at least one of
143 	 * -[rtlacDR].  The "-d" option is, well, optional.  We don't
144 	 * care if it's there or not.
145 	 */
146 	rtlacDRflag = rflag + tflag + lflag + aflag + cflag + Dflag + Rflag;
147 	if ((iflag != 0 && rtlacDRflag != 0) ||
148 	    (iflag == 0 && rtlacDRflag == 0)) {
149 		usage();
150 		exit(1);
151 	}
152 
153 	if (Dflag && atoi(delay) <= 0) {
154 		(void) fprintf(stderr, "Invalid arguments: -D %s\n", delay);
155 		usage();
156 		exit(1);
157 	}
158 
159 	if (Rflag && atoi(rate) <= 0) {
160 		(void) fprintf(stderr, "Invalid arguments: -R %s\n", rate);
161 		usage();
162 		exit(1);
163 	}
164 
165 	/*
166 	 * Open the keyboard device
167 	 */
168 	if ((kbd = open(kbdname, O_RDWR)) < 0) {
169 		perror("opening the keyboard");
170 		(void) fprintf(stderr, "kbd: Cannot open %s\n", kbdname);
171 		exit(1);
172 	}
173 
174 	if (iflag) {
175 		kbd_defaults(kbd);
176 		exit(0);	/* A mutually exclusive option */
177 		/*NOTREACHED*/
178 	}
179 
180 	if (tflag)
181 		get_type(kbd);
182 
183 	if (lflag)
184 		get_layout(kbd);
185 
186 	if (cflag && (error = click(copt, kbd)) != 0)
187 		exit(error);
188 
189 	if (rflag)
190 		reset(kbd);
191 
192 	if (aflag && (error = abort_enable(aopt, kbd)) != 0)
193 		exit(error);
194 
195 	if (Dflag && (error = set_repeat_delay(delay, kbd)) != 0)
196 		exit(error);
197 
198 	if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0)
199 		exit(error);
200 
201 	return (0);
202 }
203 
204 /*
205  * this routine resets the state of the keyboard as if power-up
206  */
207 static void
208 reset(int kbd)
209 {
210 	int cmd;
211 
212 	cmd = KBD_CMD_RESET;
213 
214 	if (ioctl(kbd, KIOCCMD, &cmd)) {
215 		perror("kbd: ioctl error");
216 		exit(1);
217 	}
218 
219 }
220 
221 /*
222  * this routine gets the type of the keyboard being used
223  */
224 static void
225 get_type(int kbd)
226 {
227 	int kbd_type;
228 
229 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
230 		perror("ioctl (kbd type)");
231 		exit(1);
232 	}
233 
234 	switch (kbd_type) {
235 
236 	case KB_SUN3:
237 		(void) printf("Type 3 Sun keyboard\n");
238 		break;
239 
240 	case KB_SUN4:
241 		(void) printf("Type 4 Sun keyboard\n");
242 		break;
243 
244 	case KB_ASCII:
245 		(void) printf("ASCII\n");
246 		break;
247 
248 	case KB_PC:
249 		(void) printf("PC\n");
250 		break;
251 
252 	case KB_USB:
253 		(void) printf("USB keyboard\n");
254 		break;
255 
256 	default:
257 		(void) printf("Unknown keyboard type\n");
258 		break;
259 	}
260 }
261 
262 /*
263  * this routine gets the layout of the keyboard being used
264  * also, included the autorepeat delay and rate being used
265  */
266 static void
267 get_layout(int kbd)
268 {
269 	int kbd_type;
270 	int kbd_layout;
271 	/* these two variables are used for getting delay&rate */
272 	int delay, rate;
273 	delay = rate = 0;
274 
275 	if (ioctl(kbd, KIOCTYPE, &kbd_type)) {
276 		perror("ioctl (kbd type)");
277 		exit(1);
278 	}
279 
280 	if (ioctl(kbd, KIOCLAYOUT, &kbd_layout)) {
281 		perror("ioctl (kbd layout)");
282 		exit(1);
283 	}
284 
285 	(void) printf("type=%d\nlayout=%d (0x%.2x)\n",
286 	    kbd_type, kbd_layout, kbd_layout);
287 
288 	/* below code is used to get the autorepeat delay and rate */
289 	if (ioctl(kbd, KIOCGRPTDELAY, &delay)) {
290 		perror("ioctl (kbd get repeat delay)");
291 		exit(1);
292 	}
293 
294 	if (ioctl(kbd, KIOCGRPTRATE, &rate)) {
295 		perror("ioctl (kbd get repeat rate)");
296 		exit(1);
297 	}
298 
299 	(void) printf("delay(ms)=%d\n", delay);
300 	(void) printf("rate(ms)=%d\n", rate);
301 }
302 
303 /*
304  * this routine enables or disables clicking of the keyboard
305  */
306 static int
307 click(char *copt, int kbd)
308 {
309 	int cmd;
310 
311 	if (strcmp(copt, "on") == 0)
312 		cmd = KBD_CMD_CLICK;
313 	else if (strcmp(copt, "off") == 0)
314 		cmd = KBD_CMD_NOCLICK;
315 	else {
316 		(void) fprintf(stderr, "wrong option -- %s\n", copt);
317 		usage();
318 		return (1);
319 	}
320 
321 	if (ioctl(kbd, KIOCCMD, &cmd)) {
322 		perror("kbd ioctl (keyclick)");
323 		return (1);
324 	}
325 	return (0);
326 }
327 
328 /*
329  * this routine enables/disables/sets BRK or abort sequence feature
330  */
331 static int
332 abort_enable(char *aopt, int kbd)
333 {
334 	int enable;
335 
336 	if (strcmp(aopt, "alternate") == 0)
337 		enable = KIOCABORTALTERNATE;
338 	else if (strcmp(aopt, "enable") == 0)
339 		enable = KIOCABORTENABLE;
340 	else if (strcmp(aopt, "disable") == 0)
341 		enable = KIOCABORTDISABLE;
342 	else {
343 		(void) fprintf(stderr, "wrong option -- %s\n", aopt);
344 		usage();
345 		return (1);
346 	}
347 
348 	if (ioctl(kbd, KIOCSKABORTEN, &enable)) {
349 		perror("kbd ioctl (abort enable)");
350 		return (1);
351 	}
352 	return (0);
353 }
354 
355 /*
356  * this routine set autorepeat delay
357  */
358 static int
359 set_repeat_delay(char *delay_str, int kbd)
360 {
361 	int delay = atoi(delay_str);
362 
363 	/*
364 	 * The error message depends on the different inputs.
365 	 * a. the input is a invalid integer(unit in ms)
366 	 * b. the input is a integer less than the minimal delay setting.
367 	 * The condition (a) has been covered by main function and set_default
368 	 * function.
369 	 */
370 	if (ioctl(kbd, KIOCSRPTDELAY, &delay) == -1) {
371 		if (delay < KIOCRPTDELAY_MIN)
372 			(void) fprintf(stderr, "kbd: specified delay %d is "
373 			    "less than minimum %d\n", delay, KIOCRPTDELAY_MIN);
374 		else
375 			perror("kbd: set repeat delay");
376 		return (1);
377 	}
378 
379 	return (0);
380 }
381 
382 /*
383  * this routine set autorepeat rate
384  */
385 static int
386 set_repeat_rate(char *rate_str, int kbd)
387 {
388 	int rate = atoi(rate_str);
389 
390 	/*
391 	 * The error message depends on the different inputs.
392 	 * a. the input is a invalid integer(unit in ms)
393 	 * b. the input is a integer less than the minimal rate setting.
394 	 * The condition (a) has been covered by main function and set_default
395 	 * function.
396 	 */
397 	if (ioctl(kbd, KIOCSRPTRATE, &rate) == -1) {
398 		if (rate < KIOCRPTRATE_MIN)
399 			(void) fprintf(stderr, "kbd: specified rate %d is "
400 			    "less than minimum %d\n", rate, KIOCRPTRATE_MIN);
401 		else
402 			perror("kbd: set repeat rate");
403 		return (1);
404 	}
405 
406 	return (0);
407 }
408 
409 #define	BAD_DEFAULT	"kbd: bad default value for %s: %s\n"
410 
411 static void
412 kbd_defaults(int kbd)
413 {
414 	char *p;
415 
416 	if (defopen(DEF_FILE) != 0) {
417 		(void) fprintf(stderr, "Can't open default file: %s\n",
418 		    DEF_FILE);
419 		exit(1);
420 	}
421 
422 	p = defread(DEF_CLICK);
423 	if (p != NULL) {
424 		/*
425 		 * KEYCLICK must equal "on" or "off"
426 		 */
427 		if ((strcmp(p, "on") == 0) || (strcmp(p, "off") == 0))
428 			(void) click(p, kbd);
429 		else
430 			(void) fprintf(stderr, BAD_DEFAULT, DEF_CLICK, p);
431 	}
432 
433 	p = defread(DEF_ABORT);
434 	if (p != NULL) {
435 		/*
436 		 * ABORT must equal "enable", "disable" or "alternate"
437 		 */
438 		if ((strcmp(p, "enable") == 0) ||
439 		    (strcmp(p, "alternate") == 0) ||
440 		    (strcmp(p, "disable") == 0))
441 			(void) abort_enable(p, kbd);
442 		else
443 			(void) fprintf(stderr, BAD_DEFAULT, DEF_ABORT, p);
444 	}
445 
446 	p = defread(DEF_RPTDELAY);
447 	if (p != NULL) {
448 		/*
449 		 * REPEAT_DELAY unit in ms
450 		 */
451 		if (atoi(p) > 0)
452 			(void) set_repeat_delay(p, kbd);
453 		else
454 			(void) fprintf(stderr, BAD_DEFAULT, DEF_RPTDELAY, p);
455 	}
456 
457 	p = defread(DEF_RPTRATE);
458 	if (p != NULL) {
459 		/*
460 		 * REPEAT_RATE unit in ms
461 		 */
462 		if (atoi(p) > 0)
463 			(void) set_repeat_rate(p, kbd);
464 		else
465 			(void) fprintf(stderr, BAD_DEFAULT, DEF_RPTRATE, p);
466 	}
467 }
468 
469 static char *usage1 = "kbd [-r] [-t] [-l] [-a enable|disable|alternate]";
470 static char *usage2 = "    [-c on|off][-D delay][-R rate][-d keyboard device]";
471 static char *usage3 = "kbd -i [-d keyboard device]";
472 
473 static void
474 usage(void)
475 {
476 	(void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n", usage1, usage2,
477 	    usage3);
478 }
479