Parent Directory | Revision Log
Revision 1.1 - (view) (download)
1 : | iskra | 1.1 | /* vi: set sw=4 ts=4: */ |
2 : | /* | ||
3 : | * loadfont.c - Eugene Crosser & Andries Brouwer | ||
4 : | * | ||
5 : | * Version 0.96bb | ||
6 : | * | ||
7 : | * Loads the console font, and possibly the corresponding screen map(s). | ||
8 : | * (Adapted for busybox by Matej Vela.) | ||
9 : | */ | ||
10 : | #include <stdio.h> | ||
11 : | #include <string.h> | ||
12 : | #include <fcntl.h> | ||
13 : | #include <memory.h> | ||
14 : | #include <stdlib.h> | ||
15 : | #include <unistd.h> | ||
16 : | #include <sys/types.h> | ||
17 : | #include <dirent.h> | ||
18 : | #include <errno.h> | ||
19 : | #include <sys/ioctl.h> | ||
20 : | #include <sys/kd.h> | ||
21 : | #include <endian.h> | ||
22 : | #include "busybox.h" | ||
23 : | |||
24 : | static const int PSF_MAGIC1 = 0x36; | ||
25 : | static const int PSF_MAGIC2 = 0x04; | ||
26 : | |||
27 : | static const int PSF_MODE512 = 0x01; | ||
28 : | static const int PSF_MODEHASTAB = 0x02; | ||
29 : | static const int PSF_MAXMODE = 0x03; | ||
30 : | static const int PSF_SEPARATOR = 0xFFFF; | ||
31 : | |||
32 : | struct psf_header { | ||
33 : | unsigned char magic1, magic2; /* Magic number */ | ||
34 : | unsigned char mode; /* PSF font mode */ | ||
35 : | unsigned char charsize; /* Character size */ | ||
36 : | }; | ||
37 : | |||
38 : | #define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2) | ||
39 : | |||
40 : | static void loadnewfont(int fd); | ||
41 : | |||
42 : | extern int loadfont_main(int argc, char **argv) | ||
43 : | { | ||
44 : | int fd; | ||
45 : | |||
46 : | if (argc != 1) | ||
47 : | show_usage(); | ||
48 : | |||
49 : | fd = open(CURRENT_VC, O_RDWR); | ||
50 : | if (fd < 0) | ||
51 : | perror_msg_and_die("Error opening " CURRENT_VC); | ||
52 : | loadnewfont(fd); | ||
53 : | |||
54 : | return EXIT_SUCCESS; | ||
55 : | } | ||
56 : | |||
57 : | static void do_loadfont(int fd, char *inbuf, int unit, int fontsize) | ||
58 : | { | ||
59 : | char buf[16384]; | ||
60 : | int i; | ||
61 : | |||
62 : | memset(buf, 0, sizeof(buf)); | ||
63 : | |||
64 : | if (unit < 1 || unit > 32) | ||
65 : | error_msg_and_die("Bad character size %d", unit); | ||
66 : | |||
67 : | for (i = 0; i < fontsize; i++) | ||
68 : | memcpy(buf + (32 * i), inbuf + (unit * i), unit); | ||
69 : | |||
70 : | #if defined( PIO_FONTX ) && !defined( __sparc__ ) | ||
71 : | { | ||
72 : | struct consolefontdesc cfd; | ||
73 : | |||
74 : | cfd.charcount = fontsize; | ||
75 : | cfd.charheight = unit; | ||
76 : | cfd.chardata = buf; | ||
77 : | |||
78 : | if (ioctl(fd, PIO_FONTX, &cfd) == 0) | ||
79 : | return; /* success */ | ||
80 : | perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)"); | ||
81 : | } | ||
82 : | #endif | ||
83 : | if (ioctl(fd, PIO_FONT, buf)) | ||
84 : | perror_msg_and_die("PIO_FONT ioctl error"); | ||
85 : | } | ||
86 : | |||
87 : | static void | ||
88 : | do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) | ||
89 : | { | ||
90 : | struct unimapinit advice; | ||
91 : | struct unimapdesc ud; | ||
92 : | struct unipair *up; | ||
93 : | int ct = 0, maxct; | ||
94 : | int glyph; | ||
95 : | u_short unicode; | ||
96 : | |||
97 : | maxct = tailsz; /* more than enough */ | ||
98 : | up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair)); | ||
99 : | |||
100 : | for (glyph = 0; glyph < fontsize; glyph++) { | ||
101 : | while (tailsz >= 2) { | ||
102 : | unicode = (((u_short) inbuf[1]) << 8) + inbuf[0]; | ||
103 : | tailsz -= 2; | ||
104 : | inbuf += 2; | ||
105 : | if (unicode == PSF_SEPARATOR) | ||
106 : | break; | ||
107 : | up[ct].unicode = unicode; | ||
108 : | up[ct].fontpos = glyph; | ||
109 : | ct++; | ||
110 : | } | ||
111 : | } | ||
112 : | |||
113 : | /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP | ||
114 : | this printf did not work on many kernels */ | ||
115 : | |||
116 : | advice.advised_hashsize = 0; | ||
117 : | advice.advised_hashstep = 0; | ||
118 : | advice.advised_hashlevel = 0; | ||
119 : | if (ioctl(fd, PIO_UNIMAPCLR, &advice)) { | ||
120 : | #ifdef ENOIOCTLCMD | ||
121 : | if (errno == ENOIOCTLCMD) { | ||
122 : | error_msg("It seems this kernel is older than 1.1.92"); | ||
123 : | error_msg_and_die("No Unicode mapping table loaded."); | ||
124 : | } else | ||
125 : | #endif | ||
126 : | perror_msg_and_die("PIO_UNIMAPCLR"); | ||
127 : | } | ||
128 : | ud.entry_ct = ct; | ||
129 : | ud.entries = up; | ||
130 : | if (ioctl(fd, PIO_UNIMAP, &ud)) { | ||
131 : | #if 0 | ||
132 : | if (errno == ENOMEM) { | ||
133 : | /* change advice parameters */ | ||
134 : | } | ||
135 : | #endif | ||
136 : | perror_msg_and_die("PIO_UNIMAP"); | ||
137 : | } | ||
138 : | } | ||
139 : | |||
140 : | static void loadnewfont(int fd) | ||
141 : | { | ||
142 : | int unit; | ||
143 : | char inbuf[32768]; /* primitive */ | ||
144 : | unsigned int inputlth, offset; | ||
145 : | |||
146 : | /* | ||
147 : | * We used to look at the length of the input file | ||
148 : | * with stat(); now that we accept compressed files, | ||
149 : | * just read the entire file. | ||
150 : | */ | ||
151 : | inputlth = fread(inbuf, 1, sizeof(inbuf), stdin); | ||
152 : | if (ferror(stdin)) | ||
153 : | perror_msg_and_die("Error reading input font"); | ||
154 : | /* use malloc/realloc in case of giant files; | ||
155 : | maybe these do not occur: 16kB for the font, | ||
156 : | and 16kB for the map leaves 32 unicode values | ||
157 : | for each font position */ | ||
158 : | if (!feof(stdin)) | ||
159 : | perror_msg_and_die("Font too large"); | ||
160 : | |||
161 : | /* test for psf first */ | ||
162 : | { | ||
163 : | struct psf_header psfhdr; | ||
164 : | int fontsize; | ||
165 : | int hastable; | ||
166 : | unsigned int head0, head; | ||
167 : | |||
168 : | if (inputlth < sizeof(struct psf_header)) | ||
169 : | goto no_psf; | ||
170 : | |||
171 : | psfhdr = *(struct psf_header *) &inbuf[0]; | ||
172 : | |||
173 : | if (!PSF_MAGIC_OK(psfhdr)) | ||
174 : | goto no_psf; | ||
175 : | |||
176 : | if (psfhdr.mode > PSF_MAXMODE) | ||
177 : | error_msg_and_die("Unsupported psf file mode"); | ||
178 : | fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256); | ||
179 : | #if !defined( PIO_FONTX ) || defined( __sparc__ ) | ||
180 : | if (fontsize != 256) | ||
181 : | error_msg_and_die("Only fontsize 256 supported"); | ||
182 : | #endif | ||
183 : | hastable = (psfhdr.mode & PSF_MODEHASTAB); | ||
184 : | unit = psfhdr.charsize; | ||
185 : | head0 = sizeof(struct psf_header); | ||
186 : | |||
187 : | head = head0 + fontsize * unit; | ||
188 : | if (head > inputlth || (!hastable && head != inputlth)) | ||
189 : | error_msg_and_die("Input file: bad length"); | ||
190 : | do_loadfont(fd, inbuf + head0, unit, fontsize); | ||
191 : | if (hastable) | ||
192 : | do_loadtable(fd, inbuf + head, inputlth - head, fontsize); | ||
193 : | return; | ||
194 : | } | ||
195 : | no_psf: | ||
196 : | |||
197 : | /* file with three code pages? */ | ||
198 : | if (inputlth == 9780) { | ||
199 : | offset = 40; | ||
200 : | unit = 16; | ||
201 : | } else { | ||
202 : | /* bare font */ | ||
203 : | if (inputlth & 0377) | ||
204 : | error_msg_and_die("Bad input file size"); | ||
205 : | offset = 0; | ||
206 : | unit = inputlth / 256; | ||
207 : | } | ||
208 : | do_loadfont(fd, inbuf + offset, unit, 256); | ||
209 : | } |
No CVS admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.1 |