| /* |
| * kdmapop.c - export getscrnmap(), loadscrnmap(), |
| * loaduniscrnmap(), loadunimap() |
| * |
| * Hide the ioctl use in this file. |
| */ |
| #include <stdio.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <linux/kd.h> |
| #include "kdmapop.h" |
| #include "nls.h" |
| #include "version.h" |
| |
| /* |
| * Linux pre-0.96 defined GIO_SCRNMAP, PIO_SCRNMAP: |
| typedef char scrnmap_t; |
| #define E_TABSZ 256 |
| #define GIO_SCRNMAP 0x4B40 |
| #define PIO_SCRNMAP 0x4B41 |
| * and Linux 0.99.14y first implemented them. |
| * Usage: |
| scrnmap_t map[E_TABSZ]; |
| ioctl(fd,GIO_SCRNMAP,map); |
| ioctl(fd,PIO_SCRNMAP,map); |
| * to read or write the kernel translation table that is |
| * applied to user application output before displaying. |
| * |
| * Before 1.3.1, the character set was completely undetermined, |
| * and if the font was in an order different from the character |
| * set in use, the user screen map was used to map application |
| * codes to font indices. (To be more precise: there were four |
| * translation tables, and this ioctl would get/set the fourth |
| * table, while the other three tables are built-in and constant.) |
| */ |
| int |
| getscrnmap(int fd, char *map) { |
| if (ioctl(fd,GIO_SCRNMAP,map)) { |
| perror("GIO_SCRNMAP"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int |
| loadscrnmap(int fd, char *map) { |
| if (ioctl(fd,PIO_SCRNMAP,map)) { |
| perror("PIO_SCRNMAP"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| /* |
| * Linux 1.3.1 introduces GIO_UNISCRNMAP, PIO_UNISCRNMAP: |
| #define GIO_UNISCRNMAP 0x4B69 |
| #define PIO_UNISCRNMAP 0x4B6A |
| * Usage: |
| unsigned short umap[E_TABSZ]; |
| ioctl(fd,GIO_UNISCRNMAP,umap); |
| ioctl(fd,PIO_UNISCRNMAP,umap); |
| * to read or write the kernel translation table that is |
| * applied to user application output before displaying. |
| * (When the console is not in utf8 mode.) |
| * |
| * The idea is that the umap values are 16-bit unicode (ucs2) |
| * values, and that the fonts will have an index giving the |
| * unicode value for each glyph, so that the kernel can match up |
| * application codes to font positions. |
| #define UNI_DIRECT_BASE 0xF000 |
| #define UNI_DIRECT_MASK 0x01FF |
| * For compatibility, and for fonts without table, the unicode |
| * values 0xF000+n, 0 <= n <= 0x01FF, acts as direct font indices. |
| * In the new scheme, the old PIO_SCRNMAP fills the kernel umap |
| * table with such direct-to-font values. |
| */ |
| |
| int |
| getuniscrnmap(int fd, unsigned short *map) { |
| if (ioctl(fd,GIO_UNISCRNMAP,map)) { |
| perror("GIO_UNISCRNMAP"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int |
| loaduniscrnmap(int fd, unsigned short *map) { |
| if (ioctl(fd,PIO_UNISCRNMAP,map)) { |
| perror("PIO_UNISCRNMAP"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| /* |
| * Linux 1.1.63 introduces GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR: |
| #define GIO_UNIMAP 0x4B66 |
| #define PIO_UNIMAP 0x4B67 |
| #define PIO_UNIMAPCLR 0x4B68 |
| * And Linux 1.1.92 implements them. |
| * Usage: |
| struct unimapinit { |
| unsigned short advised_hashsize; |
| unsigned short advised_hashstep; |
| unsigned short advised_hashlevel; |
| } ui; |
| ioctl(fd, PIO_UNIMAPCLR, &ui); |
| * to clear the unimap table and advise about the kind of |
| * hash setup appropriate to what one is going to load |
| * (with 0 for "don't care"). |
| struct unipair { |
| unsigned short unicode; |
| unsigned short fontpos; |
| }; |
| struct unimapdesc { |
| unsigned short entry_ct; |
| struct unipair *entries; |
| } ud; |
| ioctl(fd, PIO_UNIMAP, &ud); |
| ioctl(fd, GIO_UNIMAP, &ud); |
| * to add the indicated pairs to the kernel unimap table |
| * or to read the kernel unimap table, where in the latter case |
| * ud.entry_ct indicated the room available. |
| * |
| * In Linux 1.3.28 the hash table was replaced by a 3-level |
| * paged table, so the contents of a struct unimapinit are |
| * no longer meaningful. |
| * |
| * Linux 2.6.1 makes GIO_UNIMAP, PIO_UNIMAP, PIO_UNIMAPCLR per-vt |
| * so that fd no longer is random. |
| */ |
| int |
| getunimap(int fd, struct unimapdesc *ud0) { |
| struct unimapdesc ud; |
| int ct; |
| |
| ud.entry_ct = 0; |
| ud.entries = 0; |
| if (ioctl(fd, GIO_UNIMAP, &ud)) { |
| if(errno != ENOMEM || ud.entry_ct == 0) { |
| perror("GIO_UNIMAP(0)"); |
| return -1; |
| } |
| ct = ud.entry_ct; |
| ud.entries = (struct unipair *) |
| malloc(ct * sizeof(struct unipair)); |
| if (ud.entries == NULL) { |
| fprintf(stderr, _("%s: out of memory\n"), progname); |
| return -1; |
| } |
| if (ioctl(fd, GIO_UNIMAP, &ud)) { |
| perror("GIO_UNIMAP"); |
| return -1; |
| } |
| if (ct != ud.entry_ct) |
| fprintf(stderr, |
| _("strange... ct changed from %d to %d\n"), |
| ct, ud.entry_ct); |
| /* someone could change the unimap between our |
| first and second ioctl, so the above errors |
| are not impossible */ |
| } |
| *ud0 = ud; |
| return 0; |
| } |
| |
| int |
| loadunimap(int fd, struct unimapinit *ui, struct unimapdesc *ud) { |
| struct unimapinit advice; |
| |
| if (ui) |
| advice = *ui; |
| else { |
| advice.advised_hashsize = 0; |
| advice.advised_hashstep = 0; |
| advice.advised_hashlevel = 0; |
| } |
| again: |
| if (ioctl(fd, PIO_UNIMAPCLR, &advice)) { |
| #ifdef ENOIOCTLCMD |
| if (errno == ENOIOCTLCMD) { |
| fprintf(stderr, |
| _("It seems this kernel is older than 1.1.92\n" |
| "No Unicode mapping table loaded.\n")); |
| } else |
| #endif |
| perror("PIO_UNIMAPCLR"); |
| return -1; |
| } |
| if (ud == NULL) |
| return 0; |
| |
| if (ioctl(fd, PIO_UNIMAP, ud)) { |
| if (errno == ENOMEM && advice.advised_hashlevel < 100) { |
| advice.advised_hashlevel++; |
| goto again; |
| } |
| perror("PIO_UNIMAP"); |
| return -1; |
| } |
| |
| return 0; |
| } |