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