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