1.06
[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
183 main( int argc, char **argv ) {
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 &&
207             (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")))
208                 print_version_and_exit();
209
210         while ( (c = getopt( argc, argv, "r:d:sv" )) != EOF ) {
211                 switch (c) {
212                 case 'r':
213                         rate = atof( optarg );
214                         break;
215                 case 'd':
216                         delay = atoi( optarg );
217                         break;
218                 case 's':
219                         silent = 1;
220                         break;
221                 default:
222                         fprintf(stderr,
223                                 _("Usage: kbdrate [-V] [-s] [-r rate] [-d delay]\n"));
224                         exit(1);
225                 }
226         }
227
228         if(KDKBDREP_ioctl_ok(rate, delay, silent))      /* m68k? */
229                 return 0;
230
231         if(KIOCSRATE_ioctl_ok(rate, delay, silent))     /* sparc? */
232                 return 0;
233
234
235         /* The ioport way */
236
237         for (i = 0; i < RATE_COUNT; i++)
238                 if (rate * 10 >= valid_rates[i]) {
239                         value &= 0x60;
240                         value |= i;
241                         break;
242                 }
243
244
245         for (i = 0; i < DELAY_COUNT; i++)
246                 if (delay <= valid_delays[i]) {
247                         value &= 0x1f;
248                         value |= i << 5;
249                         break;
250                 }
251
252         if ( (fd = open( "/dev/port", O_RDWR )) < 0) {
253                 perror( _("Cannot open /dev/port") );
254                 exit( 1 );
255         }
256
257         do {
258                 lseek( fd, 0x64, 0 );
259                 read( fd, &data, 1 );
260         } while ((data & 2) == 2 );  /* wait */
261
262         lseek( fd, 0x60, 0 );
263         data = 0xf3;                 /* set typematic rate */
264         write( fd, &data, 1 );
265
266         do {
267                 lseek( fd, 0x64, 0 );
268                 read( fd, &data, 1 );
269         } while ((data & 2) == 2 );  /* wait */
270
271         lseek( fd, 0x60, 0 );
272         sleep( 1 );
273         write( fd, &value, 1 );
274
275         close( fd );
276
277         if (!silent)
278                 printf( _("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
279                         valid_rates[value & 0x1f] / 10.0,
280                         valid_delays[ (value & 0x60) >> 5 ] );
281
282         return 0;
283 }