#include <linux/workqueue.h>
#include <linux/bootmem.h>
#include <linux/pm.h>
-#include <linux/font.h>
#include <asm/io.h>
#include <asm/system.h>
#define max_font_size 65536
-int con_font_get(int currcons, struct console_font_op *op)
+int con_font_op(int currcons, struct console_font_op *op)
{
- struct console_font font;
int rc = -EINVAL;
- int c;
+ int size = max_font_size, set;
+ u8 *temp = NULL;
+ struct console_font_op old_op;
if (vt_cons[currcons]->vc_mode != KD_TEXT)
- return -EINVAL;
-
+ goto quit;
+ memcpy(&old_op, op, sizeof(old_op));
+ if (op->op == KD_FONT_OP_SET) {
+ if (!op->data)
+ return -EINVAL;
+ if (op->charcount > 512)
+ goto quit;
+ if (!op->height) { /* Need to guess font height [compat] */
+ int h, i;
+ u8 __user *charmap = op->data;
+ u8 tmp;
+
+ /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+ so that we can get rid of this soon */
+ if (!(op->flags & KD_FONT_FLAG_OLD))
+ goto quit;
+ rc = -EFAULT;
+ for (h = 32; h > 0; h--)
+ for (i = 0; i < op->charcount; i++) {
+ if (get_user(tmp, &charmap[32*i+h-1]))
+ goto quit;
+ if (tmp)
+ goto nonzero;
+ }
+ rc = -EINVAL;
+ goto quit;
+ nonzero:
+ rc = -EINVAL;
+ op->height = h;
+ }
+ if (op->width > 32 || op->height > 32)
+ goto quit;
+ size = (op->width+7)/8 * 32 * op->charcount;
+ if (size > max_font_size)
+ return -ENOSPC;
+ set = 1;
+ } else if (op->op == KD_FONT_OP_GET)
+ set = 0;
+ else {
+ acquire_console_sem();
+ rc = sw->con_font_op(vc_cons[currcons].d, op);
+ release_console_sem();
+ return rc;
+ }
if (op->data) {
- font.data = kmalloc(max_font_size, GFP_KERNEL);
- if (!font.data)
+ temp = kmalloc(size, GFP_KERNEL);
+ if (!temp)
return -ENOMEM;
- } else
- font.data = NULL;
-
- acquire_console_sem();
- if (sw->con_font_get)
- rc = sw->con_font_get(vc_cons[currcons].d, &font);
- else
- rc = -ENOSYS;
- release_console_sem();
-
- if (rc)
- goto out;
-
- c = (font.width+7)/8 * 32 * font.charcount;
-
- if (op->data && font.charcount > op->charcount)
- rc = -ENOSPC;
- if (!(op->flags & KD_FONT_FLAG_OLD)) {
- if (font.width > op->width || font.height > op->height)
- rc = -ENOSPC;
- } else {
- if (font.width != 8)
- rc = -EIO;
- else if ((op->height && font.height > op->height) ||
- font.height > 32)
- rc = -ENOSPC;
+ if (set && copy_from_user(temp, op->data, size)) {
+ rc = -EFAULT;
+ goto quit;
+ }
+ op->data = temp;
}
- if (rc)
- goto out;
-
- if (op->data && copy_to_user(op->data, font.data, c))
- rc = -EFAULT;
-
-out:
- kfree(font.data);
- return rc;
-}
-
-int con_font_set(int currcons, struct console_font_op *op)
-{
- struct console_font font;
- int rc = -EINVAL;
- int size;
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
- return -EINVAL;
- if (!op->data)
- return -EINVAL;
- if (op->charcount > 512)
- return -EINVAL;
- if (!op->height) { /* Need to guess font height [compat] */
- int h, i;
- u8 __user *charmap = op->data;
- u8 tmp;
-
- /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
- so that we can get rid of this soon */
- if (!(op->flags & KD_FONT_FLAG_OLD))
- return -EINVAL;
- for (h = 32; h > 0; h--)
- for (i = 0; i < op->charcount; i++) {
- if (get_user(tmp, &charmap[32*i+h-1]))
- return -EFAULT;
- if (tmp)
- goto nonzero;
- }
- return -EINVAL;
- nonzero:
- op->height = h;
- }
- if (op->width <= 0 || op->width > 32 || op->height > 32)
- return -EINVAL;
- size = (op->width+7)/8 * 32 * op->charcount;
- if (size > max_font_size)
- return -ENOSPC;
- font.charcount = op->charcount;
- font.height = op->height;
- font.width = op->width;
- font.data = kmalloc(size, GFP_KERNEL);
- if (!font.data)
- return -ENOMEM;
- if (copy_from_user(font.data, op->data, size)) {
- kfree(font.data);
- return -EFAULT;
- }
acquire_console_sem();
- if (sw->con_font_set)
- rc = sw->con_font_set(vc_cons[currcons].d, &font, op->flags);
- else
- rc = -ENOSYS;
+ rc = sw->con_font_op(vc_cons[currcons].d, op);
release_console_sem();
- kfree(font.data);
- return rc;
-}
-
-int con_font_default(int currcons, struct console_font_op *op)
-{
- struct console_font font = {.width = op->width, .height = op->height};
- char name[MAX_FONT_NAME];
- char *s = name;
- int rc;
-
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
- return -EINVAL;
-
- if (!op->data)
- s = NULL;
- else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
- return -EFAULT;
- else
- name[MAX_FONT_NAME - 1] = 0;
- acquire_console_sem();
- if (sw->con_font_default)
- rc = sw->con_font_default(vc_cons[currcons].d, &font, s);
- else
- rc = -ENOSYS;
- release_console_sem();
- if (!rc) {
- op->width = font.width;
- op->height = font.height;
+ op->data = old_op.data;
+ if (!rc && !set) {
+ int c = (op->width+7)/8 * 32 * op->charcount;
+
+ if (op->data && op->charcount > old_op.charcount)
+ rc = -ENOSPC;
+ if (!(op->flags & KD_FONT_FLAG_OLD)) {
+ if (op->width > old_op.width ||
+ op->height > old_op.height)
+ rc = -ENOSPC;
+ } else {
+ if (op->width != 8)
+ rc = -EIO;
+ else if ((old_op.height && op->height > old_op.height) ||
+ op->height > 32)
+ rc = -ENOSPC;
+ }
+ if (!rc && op->data && copy_to_user(op->data, temp, c))
+ rc = -EFAULT;
}
+quit: if (temp)
+ kfree(temp);
return rc;
}
-int con_font_copy(int currcons, struct console_font_op *op)
-{
- int con = op->height;
- struct vc_data *vc;
- int rc;
-
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
- return -EINVAL;
-
- acquire_console_sem();
- vc = vc_cons[currcons].d;
- if (!sw->con_font_copy)
- rc = -ENOSYS;
- else if (con < 0 || !vc_cons_allocated(con))
- rc = -ENOTTY;
- else if (con == vc->vc_num) /* nothing to do */
- rc = 0;
- else
- rc = sw->con_font_copy(vc, con);
- release_console_sem();
- return rc;
-}
-
-int con_font_op(int currcons, struct console_font_op *op)
-{
- switch (op->op) {
- case KD_FONT_OP_SET:
- return con_font_set(currcons, op);
- case KD_FONT_OP_GET:
- return con_font_get(currcons, op);
- case KD_FONT_OP_SET_DEFAULT:
- return con_font_default(currcons, op);
- case KD_FONT_OP_COPY:
- return con_font_copy(currcons, op);
- }
- return -ENOSYS;
-}
-
/*
* Interface exported to selection and vcs.
*/