Add pancyrillic font
[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  * Linux 2.6.1 makes GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR per-vt
132  * so that fd no longer is random.
133  */
134 int
135 getunimap(int fd, struct unimapdesc *ud0) {
136         struct unimapdesc ud;
137         int ct;
138
139         ud.entry_ct = 0;
140         ud.entries = 0;
141         if (ioctl(fd, GIO_UNIMAP, &ud)) {
142                 if(errno != ENOMEM || ud.entry_ct == 0) {
143                         perror("GIO_UNIMAP(0)");
144                         return -1;
145                 }
146                 ct = ud.entry_ct;
147                 ud.entries = (struct unipair *)
148                         malloc(ct * sizeof(struct unipair));
149                 if (ud.entries == NULL) {
150                         fprintf(stderr, _("%s: out of memory\n"), progname);
151                         return -1;
152                 }
153                 if (ioctl(fd, GIO_UNIMAP, &ud)) {
154                         perror("GIO_UNIMAP");
155                         return -1;
156                 }
157                 if (ct != ud.entry_ct)
158                         fprintf(stderr,
159                                 _("strange... ct changed from %d to %d\n"),
160                                 ct, ud.entry_ct);
161                 /* someone could change the unimap between our
162                    first and second ioctl, so the above errors
163                    are not impossible */
164         }
165         *ud0 = ud;
166         return 0;
167 }
168
169 int
170 loadunimap(int fd, struct unimapinit *ui, struct unimapdesc *ud) {
171         struct unimapinit advice;
172
173         if (ui)
174                 advice = *ui;
175         else {
176                 advice.advised_hashsize = 0;
177                 advice.advised_hashstep = 0;
178                 advice.advised_hashlevel = 0;
179         }
180  again:
181         if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
182 #ifdef ENOIOCTLCMD
183                 if (errno == ENOIOCTLCMD) {
184                         fprintf(stderr,
185                                 _("It seems this kernel is older than 1.1.92\n"
186                                   "No Unicode mapping table loaded.\n"));
187                 } else
188 #endif
189                 perror("PIO_UNIMAPCLR");
190                 return -1;
191         }
192         if (ud == NULL)
193                 return 0;
194
195         if (ioctl(fd, PIO_UNIMAP, ud)) {
196                 if (errno == ENOMEM && advice.advised_hashlevel < 100) {
197                         advice.advised_hashlevel++;
198                         goto again;
199                 }
200                 perror("PIO_UNIMAP");
201                 return -1;
202         }
203
204         return 0;
205 }