I just upgraded an HP Jornada 720 from NetBSD 2.0 to NetBSD 7.1, and discovered the wscons keymaps were broken in the meantime: it is impossible to change the keymap using wsconsctl encoding or wsconsctl map. Both commands succeed but have no effect.
After poking a few printf in the kernel, I found this in src/sys/dev/hpc/hpckbd.c: /* fix keydesc table */ /* * XXX The way this is done is really wrong. The __UNCONST() * is a hint as to what is wrong. This actually ends up modifying * initialized data which is marked "const". * The reason we get away with it here is apparently that text * and read-only data gets mapped read/write on the platforms * using this code. */ desc = (struct wscons_keydesc *)__UNCONST(hpckbd_keymapdata.keydesc); for (i = 0; desc[i].name != 0; i++) { if ((desc[i].name & KB_MACHDEP) && desc[i].map == NULL) { desc[i].map = map; desc[i].map_size = mapsize; } } I managed to restore wscons keymaps by copying hpckbd_keymapdata.keydesc into a malloc() buffer and changing the hpckbd_keymapdata.keydesc to the new location, which is mapped read/write. The offending code did not change since NetBSD 2.0, except the XXX comment added in 2015. That suggests the compiler behavior changed about initalized const data, which was still mapped R/W in the ancient time and is now really read-only, altough it accepts nilpotent writes without raising an exception. Is the patch below fine to commit, or is there a smarter way to sort this out? I am not sure why hpc(adm|mips|sh) ports need to patch this const data and if it can be done differently. Another point: In order to have french keymap, I used to do wsconsctl -w encoding=fr, and I must now do wsconsctl -w encoding=fr.machdep. I wonder ig it is on purpose or if it is a bug (that is: should the KB_MACHDEP flag be filtered somewhere?) --- sys/dev/hpc/hpckbd.c 27 Oct 2012 17:18:17 -0000 1.30 +++ sys/dev/hpc/hpckbd.c 9 Jun 2017 15:34:42 -0000 @@ -34,8 +34,9 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/malloc.h> #include <sys/tty.h> #include <sys/bus.h> @@ -263,24 +264,32 @@ hpckbd_keymap_setup(struct hpckbd_core *hc, const keysym_t *map, int mapsize) { int i; - struct wscons_keydesc *desc; + const struct wscons_keydesc *desc; + static struct wscons_keydesc *ndesc = NULL; - /* fix keydesc table */ /* - * XXX The way this is done is really wrong. The __UNCONST() - * is a hint as to what is wrong. This actually ends up modifying - * initialized data which is marked "const". - * The reason we get away with it here is apparently that text - * and read-only data gets mapped read/write on the platforms - * using this code. + * fix keydesc table. Since it is const data, we must + * copy it once before changingg it. */ - desc = (struct wscons_keydesc *)__UNCONST(hpckbd_keymapdata.keydesc); + + if (ndesc == NULL) { + size_t sz; + + for (sz = 0; hpckbd_keymapdata.keydesc[sz].name != 0; sz++); + + ndesc = malloc(sz * sizeof(*ndesc), M_DEVBUF, M_WAITOK); + memcpy(ndesc, hpckbd_keymapdata.keydesc, sz * sizeof(*ndesc)); + + hpckbd_keymapdata.keydesc = ndesc; + } + + desc = hpckbd_keymapdata.keydesc; for (i = 0; desc[i].name != 0; i++) { if ((desc[i].name & KB_MACHDEP) && desc[i].map == NULL) { - desc[i].map = map; - desc[i].map_size = mapsize; + ndesc[i].map = map; + ndesc[i].map_size = mapsize; } } return; -- Emmanuel Dreyfus http://hcpnet.free.fr/pubz m...@netbsd.org