99faf0e9e8480a5658044f206d5f17fcdd98db75
[platform/upstream/kbd.git] / src / kdmapop.c
1 /*
2  * kdmapop.c - export getscrnmap(), loadscrnmap(),
3  *                    loaduniscrnmap(), loadunimap()
4  *
5  * Hide the ioctl use in this file.
6  */
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <sys/ioctl.h>
11 #include <linux/kd.h>
12 #include "kdmapop.h"
13 #include "nls.h"
14 #include "version.h"
15
16 /*
17  * Linux pre-0.96 defined GIO_SCRNMAP, PIO_SCRNMAP:
18         typedef char scrnmap_t;
19         #define E_TABSZ         256
20         #define GIO_SCRNMAP     0x4B40
21         #define PIO_SCRNMAP     0x4B41
22  * and Linux 0.99.14y first implemented them.
23  * Usage:
24         scrnmap_t map[E_TABSZ];
25         ioctl(fd,GIO_SCRNMAP,map);
26         ioctl(fd,PIO_SCRNMAP,map);
27  * to read or write the kernel translation table that is
28  * applied to user application output before displaying.
29  *
30  * Before 1.3.1, the character set was completely undetermined,
31  * and if the font was in an order different from the character
32  * set in use, the user screen map was used to map application
33  * codes to font indices. (To be more precise: there were four
34  * translation tables, and this ioctl would get/set the fourth
35  * table, while the other three tables are built-in and constant.)
36  */
37 int
38 getscrnmap(int fd, char *map) {
39         if (ioctl(fd,GIO_SCRNMAP,map)) {
40                 perror("GIO_SCRNMAP");
41                 return -1;
42         }
43         return 0;
44 }
45
46 int
47 loadscrnmap(int fd, char *map) {
48         if (ioctl(fd,PIO_SCRNMAP,map)) {
49                 perror("PIO_SCRNMAP");
50                 return -1;
51         }
52         return 0;
53 }
54
55 /*
56  * Linux 1.3.1 introduces GIO_UNISCRNMAP, PIO_UNISCRNMAP:
57         #define GIO_UNISCRNMAP  0x4B69
58         #define PIO_UNISCRNMAP  0x4B6A
59  * Usage:
60         unsigned short umap[E_TABSZ];
61         ioctl(fd,GIO_UNISCRNMAP,umap);
62         ioctl(fd,PIO_UNISCRNMAP,umap);
63  * to read or write the kernel translation table that is
64  * applied to user application output before displaying.
65  * (When the console is not in utf8 mode.)
66  *
67  * The idea is that the umap values are 16-bit unicode (ucs2)
68  * values, and that the fonts will have an index giving the
69  * unicode value for each glyph, so that the kernel can match up
70  * application codes to font positions.
71         #define UNI_DIRECT_BASE 0xF000
72         #define UNI_DIRECT_MASK 0x01FF
73  * For compatibility, and for fonts without table, the unicode
74  * values 0xF000+n, 0 <= n <= 0x01FF, acts as direct font indices.
75  * In the new scheme, the old PIO_SCRNMAP fills the kernel umap
76  * table with such direct-to-font values.
77  */
78         
79 int
80 getuniscrnmap(int fd, unsigned short *map) {
81         if (ioctl(fd,GIO_UNISCRNMAP,map)) {
82                 perror("GIO_UNISCRNMAP");
83                 return -1;
84         }
85         return 0;
86 }
87
88 int
89 loaduniscrnmap(int fd, unsigned short *map) {
90         if (ioctl(fd,PIO_UNISCRNMAP,map)) {
91                 perror("PIO_UNISCRNMAP");
92                 return -1;
93         }
94         return 0;
95 }
96
97 /*
98  * Linux 1.1.63 introduces GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR:
99         #define GIO_UNIMAP     0x4B66
100         #define PIO_UNIMAP     0x4B67
101         #define PIO_UNIMAPCLR  0x4B68
102  * And Linux 1.1.92 implements them.
103  * Usage:
104         struct unimapinit {
105                 unsigned short advised_hashsize;
106                 unsigned short advised_hashstep;
107                 unsigned short advised_hashlevel;
108         } ui;
109         ioctl(fd, PIO_UNIMAPCLR, &ui);
110  * to clear the unimap table and advise about the kind of
111  * hash setup appropriate to what one is going to load
112  * (with 0 for "don't care").
113         struct unipair {
114                 unsigned short unicode;
115                 unsigned short fontpos;
116         };
117         struct unimapdesc {
118                 unsigned short entry_ct;
119                 struct unipair *entries;
120         } ud;
121         ioctl(fd, PIO_UNIMAP, &ud);
122         ioctl(fd, GIO_UNIMAP, &ud);
123  * to add the indicated pairs to the kernel unimap table
124  * or to read the kernel unimap table, where in the latter case
125  * ud.entry_ct indicated the room available.
126  *
127  * In Linux 1.3.28 the hash table was replaced by a 3-level
128  * paged table, so the contents of a struct unimapinit are
129  * no longer meaningful.
130  */
131 int
132 getunimap(int fd, struct unimapdesc *ud0) {
133         struct unimapdesc ud;
134         int ct;
135
136         ud.entry_ct = 0;
137         ud.entries = 0;
138         if (ioctl(fd, GIO_UNIMAP, &ud)) {
139                 if(errno != ENOMEM || ud.entry_ct == 0) {
140                         perror("GIO_UNIMAP(0)");
141                         return -1;
142                 }
143                 ct = ud.entry_ct;
144                 ud.entries = (struct unipair *)
145                         malloc(ct * sizeof(struct unipair));
146                 if (ud.entries == NULL) {
147                         fprintf(stderr, _("%s: out of memory\n"), progname);
148                         return -1;
149                 }
150                 if (ioctl(fd, GIO_UNIMAP, &ud)) {
151                         perror("GIO_UNIMAP");
152                         return -1;
153                 }
154                 if (ct != ud.entry_ct)
155                         fprintf(stderr,
156                                 _("strange... ct changed from %d to %d\n"),
157                                 ct, ud.entry_ct);
158                 /* someone could change the unimap between our
159                    first and second ioctl, so the above errors
160                    are not impossible */
161         }
162         *ud0 = ud;
163         return 0;
164 }
165
166 int
167 loadunimap(int fd, struct unimapinit *ui, struct unimapdesc *ud) {
168         struct unimapinit advice;
169
170         if (ui)
171                 advice = *ui;
172         else {
173                 advice.advised_hashsize = 0;
174                 advice.advised_hashstep = 0;
175                 advice.advised_hashlevel = 0;
176         }
177  again:
178         if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
179 #ifdef ENOIOCTLCMD
180                 if (errno == ENOIOCTLCMD) {
181                         fprintf(stderr,
182                                 _("It seems this kernel is older than 1.1.92\n"
183                                   "No Unicode mapping table loaded.\n"));
184                 } else
185 #endif
186                 perror("PIO_UNIMAPCLR");
187                 return -1;
188         }
189         if (ud == NULL)
190                 return 0;
191
192         if (ioctl(fd, PIO_UNIMAP, ud)) {
193                 if (errno == ENOMEM && advice.advised_hashlevel < 100) {
194                         advice.advised_hashlevel++;
195                         goto again;
196                 }
197                 perror("PIO_UNIMAP");
198                 return -1;
199         }
200
201         return 0;
202 }