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