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