summaryrefslogtreecommitdiffstats
path: root/drivers/tty/vt
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r--drivers/tty/vt/consolemap.c54
-rw-r--r--drivers/tty/vt/vt.c89
2 files changed, 102 insertions, 41 deletions
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 2978ca5..610b720 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -179,7 +179,6 @@ struct uni_pagedir {
unsigned long sum;
unsigned char *inverse_translations[4];
u16 *inverse_trans_unicode;
- int readonly;
};
static struct uni_pagedir *dflt;
@@ -262,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
int m;
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
- else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
+ else if (!(p = *conp->vc_uni_pagedir_loc))
return glyph;
else if (use_unicode) {
if (!p->inverse_trans_unicode)
@@ -287,7 +286,7 @@ static void update_user_maps(void)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
- p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ p = *vc_cons[i].d->vc_uni_pagedir_loc;
if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
set_inverse_trans_unicode(vc_cons[i].d, p);
@@ -418,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
if (!p)
return;
- *vc->vc_uni_pagedir_loc = 0;
+ *vc->vc_uni_pagedir_loc = NULL;
if (--p->refcount)
return;
con_release_unimap(p);
@@ -436,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
- q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ q = *vc_cons[i].d->vc_uni_pagedir_loc;
if (!q || q == p || q->sum != p->sum)
continue;
for (j = 0; j < 32; j++) {
@@ -459,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
}
if (j == 32) {
q->refcount++;
- *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ *conp->vc_uni_pagedir_loc = q;
con_release_unimap(p);
kfree(p);
return 1;
@@ -500,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p && p->readonly)
- return -EIO;
-
+ p = *vc->vc_uni_pagedir_loc;
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
@@ -512,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return -ENOMEM;
}
q->refcount=1;
- *vc->vc_uni_pagedir_loc = (unsigned long)q;
+ *vc->vc_uni_pagedir_loc = q;
} else {
if (p == dflt) dflt = NULL;
p->refcount++;
@@ -536,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int err = 0, err1, i;
struct uni_pagedir *p, *q;
+ if (!ct)
+ return 0;
+
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p->readonly) {
- console_unlock();
- return -EIO;
- }
-
- if (!ct) {
- console_unlock();
- return 0;
- }
+ p = *vc->vc_uni_pagedir_loc;
if (p->refcount > 1) {
int j, k;
@@ -564,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Since refcount was > 1, con_clear_unimap() allocated a
* a new uni_pagedir for this vc. Re: p != q
*/
- q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ q = *vc->vc_uni_pagedir_loc;
/*
* uni_pgdir is a 32*32*64 table with rows allocated
@@ -586,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_insert_unipair(q, l, p2[k]);
if (err1) {
p->refcount++;
- *vc->vc_uni_pagedir_loc = (unsigned long)p;
+ *vc->vc_uni_pagedir_loc = p;
con_release_unimap(q);
kfree(q);
console_unlock();
@@ -655,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)
struct uni_pagedir *p;
if (dflt) {
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
dflt->refcount++;
- *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
+ *vc->vc_uni_pagedir_loc = dflt;
if (p && !--p->refcount) {
con_release_unimap(p);
kfree(p);
@@ -674,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)
if (err)
return err;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
q = dfont_unitable;
for (i = 0; i < 256; i++)
@@ -685,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)
}
if (con_unify_unimap(vc, p)) {
- dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ dflt = *vc->vc_uni_pagedir_loc;
return err;
}
@@ -713,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
return 0;
con_free_unimap(dst_vc);
- q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
+ q = *src_vc->vc_uni_pagedir_loc;
q->refcount++;
- *dst_vc->vc_uni_pagedir_loc = (long)q;
+ *dst_vc->vc_uni_pagedir_loc = q;
return 0;
}
EXPORT_SYMBOL(con_copy_unimap);
@@ -737,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
for (i = 0; i < 32; i++)
if ((p1 = p->uni_pgdir[i]))
for (j = 0; j < 32; j++)
@@ -810,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
if (!*conp->vc_uni_pagedir_loc)
return -3;
- p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ p = *conp->vc_uni_pagedir_loc;
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
(p2 = p1[(ucs >> 6) & 0x1f]) &&
(h = p2[ucs & 0x3f]) < MAX_GLYPH)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 3c00dcb..b33b00b 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)
vc->vc_num = num;
vc->vc_display_fg = &master_display_fg;
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
- vc->vc_uni_pagedir = 0;
+ vc->vc_uni_pagedir = NULL;
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
@@ -1231,6 +1231,52 @@ static void default_attr(struct vc_data *vc)
vc->vc_color = vc->vc_def_color;
}
+struct rgb { u8 r; u8 g; u8 b; };
+
+struct rgb rgb_from_256(int i)
+{
+ struct rgb c;
+ if (i < 8) { /* Standard colours. */
+ c.r = i&1 ? 0xaa : 0x00;
+ c.g = i&2 ? 0xaa : 0x00;
+ c.b = i&4 ? 0xaa : 0x00;
+ } else if (i < 16) {
+ c.r = i&1 ? 0xff : 0x55;
+ c.g = i&2 ? 0xff : 0x55;
+ c.b = i&4 ? 0xff : 0x55;
+ } else if (i < 232) { /* 6x6x6 colour cube. */
+ c.r = (i - 16) / 36 * 85 / 2;
+ c.g = (i - 16) / 6 % 6 * 85 / 2;
+ c.b = (i - 16) % 6 * 85 / 2;
+ } else /* Grayscale ramp. */
+ c.r = c.g = c.b = i * 10 - 2312;
+ return c;
+}
+
+static void rgb_foreground(struct vc_data *vc, struct rgb c)
+{
+ u8 hue, max = c.r;
+ if (c.g > max)
+ max = c.g;
+ if (c.b > max)
+ max = c.b;
+ hue = (c.r > max/2 ? 4 : 0)
+ | (c.g > max/2 ? 2 : 0)
+ | (c.b > max/2 ? 1 : 0);
+ if (hue == 7 && max <= 0x55)
+ hue = 0, vc->vc_intensity = 2;
+ else
+ vc->vc_intensity = (max > 0xaa) + 1;
+ vc->vc_color = (vc->vc_color & 0xf0) | hue;
+}
+
+static void rgb_background(struct vc_data *vc, struct rgb c)
+{
+ /* For backgrounds, err on the dark side. */
+ vc->vc_color = (vc->vc_color & 0x0f)
+ | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
+}
+
/* console_lock is held */
static void csi_m(struct vc_data *vc)
{
@@ -1302,8 +1348,7 @@ static void csi_m(struct vc_data *vc)
case 27:
vc->vc_reverse = 0;
break;
- case 38:
- case 48: /* ITU T.416
+ case 38: /* ITU T.416
* Higher colour modes.
* They break the usual properties of SGR codes
* and thus need to be detected and ignored by
@@ -1315,15 +1360,41 @@ static void csi_m(struct vc_data *vc)
i++;
if (i > vc->vc_npar)
break;
- if (vc->vc_par[i] == 5) /* 256 colours */
- i++; /* ubiquitous */
- else if (vc->vc_par[i] == 2) /* 24 bit colours */
- i += 3; /* extremely rare */
+ if (vc->vc_par[i] == 5 && /* 256 colours */
+ i < vc->vc_npar) { /* ubiquitous */
+ i++;
+ rgb_foreground(vc,
+ rgb_from_256(vc->vc_par[i]));
+ } else if (vc->vc_par[i] == 2 && /* 24 bit */
+ i <= vc->vc_npar + 3) {/* extremely rare */
+ struct rgb c = {r:vc->vc_par[i+1],
+ g:vc->vc_par[i+2],
+ b:vc->vc_par[i+3]};
+ rgb_foreground(vc, c);
+ i += 3;
+ }
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
- * that detecting them is not worth the few extra
- * bytes of kernel's size.
+ * there's no point in supporting them.
*/
break;
+ case 48:
+ i++;
+ if (i > vc->vc_npar)
+ break;
+ if (vc->vc_par[i] == 5 && /* 256 colours */
+ i < vc->vc_npar) {
+ i++;
+ rgb_background(vc,
+ rgb_from_256(vc->vc_par[i]));
+ } else if (vc->vc_par[i] == 2 && /* 24 bit */
+ i <= vc->vc_npar + 3) {
+ struct rgb c = {r:vc->vc_par[i+1],
+ g:vc->vc_par[i+2],
+ b:vc->vc_par[i+3]};
+ rgb_background(vc, c);
+ i += 3;
+ }
+ break;
case 39:
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
break;
OpenPOWER on IntegriCloud