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