Revert "[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 (since 2.1.30),
67   with yet another 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         int period;       /* in msec; <= 0: don't change */
89 };
90 #endif
91
92 #include <signal.h>
93
94 #include "nls.h"
95 #include "version.h"
96
97 static int valid_rates[] = { 300, 267, 240, 218, 200, 185, 171, 160, 150,
98                                    133, 120, 109, 100, 92, 86, 80, 75, 67,
99                                    60, 55, 50, 46, 43, 40, 37, 33, 30, 27,
100                                    25, 23, 21, 20 };
101 #define RATE_COUNT (sizeof( valid_rates ) / sizeof( int ))
102
103 static int valid_delays[] = { 250, 500, 750, 1000 };
104 #define DELAY_COUNT (sizeof( valid_delays ) / sizeof( int ))
105
106 static int
107 KDKBDREP_ioctl_ok(double rate, int delay, int silent) {
108 #if defined(KDKBDREP) && !defined(__sparc__)
109         /* This ioctl is defined in <linux/kd.h> but is not
110            implemented anywhere - must be in some m68k patches.
111            We cannot blindly try unimplemented ioctls on sparc64 -
112            the 32<->64bit transition layer does not like it. */
113         struct kbd_repeat kbdrep_s;
114
115         /* don't change, just test */
116         kbdrep_s.period = -1;
117         kbdrep_s.delay = -1;
118         if (ioctl( 0, KDKBDREP, &kbdrep_s )) {
119                 if (errno == EINVAL || errno == ENOTTY)
120                         return 0;
121                 perror( "ioctl(KDKBDREP)" );
122                 exit( 1 );
123         }
124
125 #if 0
126         printf("old delay %d, period %d\n",
127                kbdrep_s.delay, kbdrep_s.period);
128 #endif
129
130         /* do the change */
131         if (rate == 0)                            /* switch repeat off */
132                 kbdrep_s.period = 0;
133         else
134                 kbdrep_s.period  = 1000.0 / rate; /* convert cps to msec */
135         if (kbdrep_s.period < 1)
136                 kbdrep_s.period = 1;
137         kbdrep_s.delay = delay;
138         if (kbdrep_s.delay < 1)
139                 kbdrep_s.delay = 1;
140    
141         if (ioctl(0, KDKBDREP, &kbdrep_s)) {
142                 perror("ioctl(KDKBDREP)");
143                 exit(1);
144         }
145
146         /* report */
147         if (kbdrep_s.period == 0)
148                 rate = 0;
149         else
150                 rate = 1000.0 / (double) kbdrep_s.period;
151
152         if (!silent)
153                 printf( _("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
154                         rate, kbdrep_s.delay );
155
156         return 1;                       /* success! */
157 #else /* no KDKBDREP or __sparc__ */
158         return 0;
159 #endif /* KDKBDREP */
160 }
161
162 static int
163 KIOCSRATE_ioctl_ok(double rate, int delay, int silent) {
164 #ifdef KIOCSRATE
165         struct kbd_rate kbdrate_s;
166         int fd;
167
168         fd = open("/dev/kbd", O_RDONLY);
169         if (fd == -1) {
170                 perror( "open(/dev/kbd)" );
171                 exit( 1 );
172         }
173
174         kbdrate_s.period = (int) (rate + 0.5);  /* round up */
175         kbdrate_s.delay = delay * HZ / 1000;  /* convert ms to Hz */
176         if (kbdrate_s.period > 50)
177                 kbdrate_s.period = 50;
178
179         if (ioctl( fd, KIOCSRATE, &kbdrate_s )) {
180                 perror( "ioctl(KIOCSRATE)" );
181                 exit( 1 );
182         }
183         close( fd );
184
185         if (!silent)
186                 printf( "Typematic Rate set to %d cps (delay = %d ms)\n",
187                         kbdrate_s.period, kbdrate_s.delay * 1000 / HZ );
188
189         return 1;
190 #else /* no KIOCSRATE */
191         return 0;
192 #endif /* KIOCSRATE */
193 }
194
195 static void
196 sigalrmhandler( int sig ) {
197         fprintf( stderr, "kbdrate: Failed waiting for kbd controller!\n" );
198         raise( SIGINT );
199 }
200
201 int
202 main( int argc, char **argv ) {
203 #ifdef __sparc__
204         double      rate = 20.0;      /* Default rate */
205         int         delay = 200;     /* Default delay */
206 #else
207         double      rate = 10.9;     /* Default rate */
208         int         delay = 250;     /* Default delay */
209 #endif
210         int         value = 0x7f;    /* Maximum delay with slowest rate */
211                                      /* DO NOT CHANGE this value */
212         int         silent = 0;
213         int         fd;
214         char        data;
215         int         c;
216         int         i;
217         extern char *optarg;
218
219         set_progname(argv[0]);
220
221         setlocale(LC_ALL, "");
222         bindtextdomain(PACKAGE, LOCALEDIR);
223         textdomain(PACKAGE);
224
225         if (argc == 2 &&
226             (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")))
227                 print_version_and_exit();
228
229         while ( (c = getopt( argc, argv, "r:d:sv" )) != EOF ) {
230                 switch (c) {
231                 case 'r':
232                         rate = atof( optarg );
233                         break;
234                 case 'd':
235                         delay = atoi( optarg );
236                         break;
237                 case 's':
238                         silent = 1;
239                         break;
240                 default:
241                         fprintf(stderr,
242                                 _("Usage: kbdrate [-V] [-s] [-r rate] [-d delay]\n"));
243                         exit(1);
244                 }
245         }
246
247         if(KDKBDREP_ioctl_ok(rate, delay, silent))      /* m68k? */
248                 return 0;
249
250         if(KIOCSRATE_ioctl_ok(rate, delay, silent))     /* sparc? */
251                 return 0;
252
253
254         /* The ioport way - will crash on sparc */
255
256 #ifndef __sparc__
257         for (i = 0; i < RATE_COUNT; i++)
258                 if (rate * 10 >= valid_rates[i]) {
259                         value &= 0x60;
260                         value |= i;
261                         break;
262                 }
263
264
265         for (i = 0; i < DELAY_COUNT; i++)
266                 if (delay <= valid_delays[i]) {
267                         value &= 0x1f;
268                         value |= i << 5;
269                         break;
270                 }
271
272         if ( (fd = open( "/dev/port", O_RDWR )) < 0) {
273                 perror( _("Cannot open /dev/port") );
274                 exit( 1 );
275         }
276
277         signal( SIGALRM, sigalrmhandler );
278         alarm( 3 );
279
280         do {
281                 lseek( fd, 0x64, 0 );
282                 if (read( fd, &data, 1 ) == -1) {
283                         perror( "read" );
284                         exit( 1 );
285                 }
286         } while ((data & 2) == 2 );  /* wait */
287
288         lseek( fd, 0x60, 0 );
289         data = 0xf3;                 /* set typematic rate */
290         if (write( fd, &data, 1 ) == -1) {
291                 perror( "write" );
292                 exit( 1 );
293         }
294
295         do {
296                 lseek( fd, 0x64, 0 );
297                 if (read( fd, &data, 1 ) == -1) {
298                         perror( "read" );
299                         exit( 1 );
300                 }
301         } while ((data & 2) == 2 );  /* wait */
302
303         alarm( 0 );
304
305         lseek( fd, 0x60, 0 );
306         sleep( 1 );
307         if (write( fd, &value, 1 ) == -1) {
308                 perror( "write" );
309                 exit( 1 );
310         }
311
312         close( fd );
313
314         if (!silent)
315                 printf( _("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
316                         valid_rates[value & 0x1f] / 10.0,
317                         valid_delays[ (value & 0x60) >> 5 ] );
318
319 #endif
320
321         return 0;
322 }