[SYSTEM] Apply patch from Debian.
[platform/upstream/kbd.git] / src / kbdrate.c
1 /*
2 From: faith@cs.unc.edu (Rik Faith)
3 Subject: User mode keyboard rate changer
4 Date: 27 Apr 92 13:44:26 GMT
5
6 I put together this program, called kbdrate.c, which will reset the keyboard
7 repeat rate and delay in user mode.  The program must have read/write
8 access to /dev/port, so if /dev/port is only read/writeable by group port,
9 then kbdrate must run setgid to group port (for example).
10
11 The "rate" is the rate in characters per second
12
13 The "delay" is the amount of time the key must remain depressed before it
14 will start to repeat.
15
16 Usage examples:
17
18 kbdrate                 set rate to IBM default (10.9 cps, 250ms delay)
19 kbdrate -r 30.0         set rate to 30 cps and delay to 250ms
20 kbdrate -r 20.0 -s      set rate to 20 cps (delay 250ms) -- don't print message
21 kbdrate -r 0 -d 0       set rate to 2.0 cps and delay to 250 ms
22
23 I find it useful to put kbdrate in my /etc/rc file so that the keyboard
24 rate is set to something that I find comfortable at boot time.  This sure
25 beats rebuilding the kernel!
26
27
28   kbdrate.c -- Set keyboard typematic rate (and delay)
29   Created: Thu Apr 23 12:24:30 1992
30   Author: Rickard E. Faith, faith@cs.unc.edu
31
32   Copyright 1992 Rickard E. Faith.  Distributed under the GPL.
33   This program comes with ABSOLUTELY NO WARRANTY.
34   Usage: kbdrate [-r rate] [-d delay] [-s]
35          Rate can range from 2.0 to 30.0 (units are characters per second)
36          Delay can range from 250 to 1000 (units are milliseconds)
37          -s suppressed message
38   Compiles under gcc 2.1 for Linux (tested with the pre-0.96 kernel)
39  
40   Wed Jun 22 21:35:43 1994, faith@cs.unc.edu:
41             Changed valid_rates per suggestion by Andries.Brouwer@cwi.nl.
42   Wed Jun 22 22:18:29 1994, faith@cs.unc.edu:
43             Added patch for AUSTIN notebooks from John Bowman
44             (bowman@hagar.ph.utexas.edu)
45  
46   Linux/68k modifications by Roman Hodek 
47                                 (Roman.Hodek@informatik.uni-erlangen.de):
48  
49   Reading/writing the Intel I/O ports via /dev/port is not the
50   English way... Such hardware dependent stuff can never work on
51   other architectures.
52   
53   Linux/68k has an new ioctl for setting the keyboard repeat rate
54   and delay. Both values are counted in msecs, the kernel will do
55   any rounding to values possible with the underlying hardware.
56  
57   kbdrate now first tries if the KDKBDREP ioctl is available. If it
58   is, it is used, else the old method is applied.
59
60   1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
61   - added Native Language Support
62
63   1999-03-17
64   Linux/SPARC modifications by Jeffrey Connell <ankh@canuck.gen.nz>:
65   It seems that the KDKBDREP ioctl is not available on this platform.
66   However, Linux/SPARC has its own ioctl for this, with yet another
67   different measurement system.  Thus, try for KIOCSRATE, too.
68
69 */
70
71 #include <stdio.h>
72 #include <unistd.h>
73 #include <stdlib.h>
74 #include <errno.h>
75 #include <sys/file.h>
76 #include <sys/ioctl.h>
77
78 #ifdef __sparc__
79 #include <asm/param.h>
80 #endif
81
82 #ifndef KDKBDREP
83 /* usually defined in <linux/kd.h> */
84 #define KDKBDREP        0x4B52  /* set keyboard delay/repeat rate;
85                                  * actually used values are returned */
86 struct kbd_repeat {
87         int delay;        /* in msec; <= 0: don't change */
88 #ifdef __sparc__
89         int rate;         /* in msec; <= 0: don't change */
90 #else
91         int period;       /* in msec; <= 0: don't change */
92 #endif
93 };
94 #endif /* KDKBDREP */
95
96 #ifdef __sparc__
97 #define KBD_PERIOD(var) var.rate
98 #else
99 #define KBD_PERIOD(var) var.period
100 #endif
101
102 #include <signal.h>
103
104 #include "nls.h"
105 #include "version.h"
106
107 static int valid_rates[] = { 300, 267, 240, 218, 200, 185, 171, 160, 150,
108                                    133, 120, 109, 100, 92, 86, 80, 75, 67,
109                                    60, 55, 50, 46, 43, 40, 37, 33, 30, 27,
110                                    25, 23, 21, 20 };
111 #define RATE_COUNT (sizeof( valid_rates ) / sizeof( int ))
112
113 static int valid_delays[] = { 250, 500, 750, 1000 };
114 #define DELAY_COUNT (sizeof( valid_delays ) / sizeof( int ))
115
116 static int
117 KDKBDREP_ioctl_ok(double rate, int delay, int silent) {
118 #if defined(KDKBDREP) && !defined(__sparc__)
119         /* This ioctl is defined in <linux/kd.h> but is not
120            implemented anywhere - must be in some m68k patches.
121            We cannot blindly try unimplemented ioctls on sparc64 -
122            the 32<->64bit transition layer does not like it. */
123         struct kbd_repeat kbdrep_s;
124
125         /* don't change, just test */
126         KBD_PERIOD(kbdrep_s) = -1;
127         kbdrep_s.delay = -1;
128         if (ioctl( 0, KDKBDREP, &kbdrep_s )) {
129                 if (errno == EINVAL || errno == ENOTTY)
130                         return 0;
131                 perror( "ioctl(KDKBDREP)" );
132                 exit( 1 );
133         }
134
135 #if 0
136         printf("old delay %d, period %d\n",
137                kbdrep_s.delay, KBD_PERIOD(kbdrep_s));
138 #endif
139
140         /* do the change */
141         if (rate == 0)                            /* switch repeat off */
142                 KBD_PERIOD(kbdrep_s) = 0;
143         else
144                 KBD_PERIOD(kbdrep_s)  = 1000.0 / rate; /* convert cps to msec */
145         if (KBD_PERIOD(kbdrep_s) < 1)
146                 KBD_PERIOD(kbdrep_s) = 1;
147         kbdrep_s.delay = delay;
148         if (kbdrep_s.delay < 1)
149                 kbdrep_s.delay = 1;
150    
151         if (ioctl(0, KDKBDREP, &kbdrep_s)) {
152                 perror("ioctl(KDKBDREP)");
153                 exit(1);
154         }
155
156         /* report */
157         if (KBD_PERIOD(kbdrep_s) == 0)
158                 rate = 0;
159         else
160                 rate = 1000.0 / (double) KBD_PERIOD(kbdrep_s);
161
162         if (!silent)
163                 printf( _("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
164                         rate, kbdrep_s.delay );
165
166         return 1;                       /* success! */
167 #else /* no KDKBDREP or __sparc__ */
168         return 0;
169 #endif /* KDKBDREP */
170 }
171
172 static int
173 KIOCSRATE_ioctl_ok(double rate, int delay, int silent) {
174 #ifdef KIOCSRATE
175         struct kbd_rate kbdrate_s;
176         int fd;
177
178         fd = open("/dev/kbd", O_RDONLY);
179         if (fd == -1) {
180                 perror( "open(/dev/kbd)" );
181                 exit( 1 );
182         }
183
184         KBD_PERIOD(kbdrate_s) = (int) (rate + 0.5);  /* round up */
185         kbdrate_s.delay = delay * HZ / 1000;  /* convert ms to Hz */
186         if (KBD_PERIOD(kbdrate_s) > 50)
187                 KBD_PERIOD(kbdrate_s) = 50;
188
189         if (ioctl( fd, KIOCSRATE, &kbdrate_s )) {
190                 perror( "ioctl(KIOCSRATE)" );
191                 exit( 1 );
192         }
193         close( fd );
194
195         if (!silent)
196                 printf( "Typematic Rate set to %d cps (delay = %d ms)\n",
197                         KBD_PERIOD(kbdrate_s), kbdrate_s.delay * 1000 / HZ );
198
199         return 1;
200 #else /* no KIOCSRATE */
201         return 0;
202 #endif /* KIOCSRATE */
203 }
204
205 void
206 sigalrmhandler( int sig ) {
207         fprintf( stderr, "kbdrate: Failed waiting for kbd controller!\n" );
208         raise( SIGINT );
209 }
210
211 int
212 main( int argc, char **argv ) {
213 #ifdef __sparc__
214         double      rate = 20.0;      /* Default rate */
215         int         delay = 200;     /* Default delay */
216 #else
217         double      rate = 10.9;     /* Default rate */
218         int         delay = 250;     /* Default delay */
219 #endif
220         int         value = 0x7f;    /* Maximum delay with slowest rate */
221                                      /* DO NOT CHANGE this value */
222         int         silent = 0;
223         int         fd;
224         char        data;
225         int         c;
226         int         i;
227         extern char *optarg;
228
229         set_progname(argv[0]);
230
231         setlocale(LC_ALL, "");
232         bindtextdomain(PACKAGE, LOCALEDIR);
233         textdomain(PACKAGE);
234
235         if (argc == 2 &&
236             (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")))
237                 print_version_and_exit();
238
239         while ( (c = getopt( argc, argv, "r:d:sv" )) != EOF ) {
240                 switch (c) {
241                 case 'r':
242                         rate = atof( optarg );
243                         break;
244                 case 'd':
245                         delay = atoi( optarg );
246                         break;
247                 case 's':
248                         silent = 1;
249                         break;
250                 default:
251                         fprintf(stderr,
252                                 _("Usage: kbdrate [-V] [-s] [-r rate] [-d delay]\n"));
253                         exit(1);
254                 }
255         }
256
257         if(KDKBDREP_ioctl_ok(rate, delay, silent))      /* m68k? */
258                 return 0;
259
260         if(KIOCSRATE_ioctl_ok(rate, delay, silent))     /* sparc? */
261                 return 0;
262
263
264         /* The ioport way - will crash on sparc */
265
266 #ifndef __sparc__
267         for (i = 0; i < RATE_COUNT; i++)
268                 if (rate * 10 >= valid_rates[i]) {
269                         value &= 0x60;
270                         value |= i;
271                         break;
272                 }
273
274
275         for (i = 0; i < DELAY_COUNT; i++)
276                 if (delay <= valid_delays[i]) {
277                         value &= 0x1f;
278                         value |= i << 5;
279                         break;
280                 }
281
282         if ( (fd = open( "/dev/port", O_RDWR )) < 0) {
283                 perror( _("Cannot open /dev/port") );
284                 exit( 1 );
285         }
286
287         signal( SIGALRM, sigalrmhandler );
288         alarm( 3 );
289
290         do {
291                 lseek( fd, 0x64, 0 );
292                 read( fd, &data, 1 );
293         } while ((data & 2) == 2 );  /* wait */
294
295         lseek( fd, 0x60, 0 );
296         data = 0xf3;                 /* set typematic rate */
297         write( fd, &data, 1 );
298
299         do {
300                 lseek( fd, 0x64, 0 );
301                 read( fd, &data, 1 );
302         } while ((data & 2) == 2 );  /* wait */
303
304         alarm( 0 );
305
306         lseek( fd, 0x60, 0 );
307         sleep( 1 );
308         write( fd, &value, 1 );
309
310         close( fd );
311
312         if (!silent)
313                 printf( _("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
314                         valid_rates[value & 0x1f] / 10.0,
315                         valid_delays[ (value & 0x60) >> 5 ] );
316
317 #endif
318
319         return 0;
320 }