#undef FBCONDEBUG
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/delay.h> /* MSch: for IRQ probe */
+#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
static int first_fb_vc;
static int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1;
-static int fbcon_has_exited;
-
/* font data */
static char fontname[40];
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
+static void fbcon_free_font(struct display *);
static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
int line, int count, int dy);
static void fbcon_modechanged(struct fb_info *info);
static void fbcon_set_all_vcs(struct fb_info *info);
-static void fbcon_start(void);
-static void fbcon_exit(void);
-static struct class_device *fbcon_class_device;
#ifdef CONFIG_MAC
/*
if (!ops || ops->currcon < 0 || rotate > 3)
return;
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
registered_fb[con2fb_map[i]] != info)
int c;
int mode;
- acquire_console_sem();
- if (ops && ops->currcon != -1)
+ if (ops->currcon != -1)
vc = vc_cons[ops->currcon].d;
if (!vc || !CON_IS_VISIBLE(vc) ||
fbcon_is_inactive(vc, info) ||
registered_fb[con2fb_map[vc->vc_num]] != info ||
- vc_cons[ops->currcon].d->vc_deccm != 1) {
- release_console_sem();
+ vc_cons[ops->currcon].d->vc_deccm != 1)
return;
- }
-
+ acquire_console_sem();
p = &fb_display[vc->vc_num];
c = scr_readw((u16 *) vc->vc_pos);
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
int i, j;
if (!this_opt || !*this_opt)
- return 1;
+ return 0;
while ((options = strsep(&this_opt, ",")) != NULL) {
if (!strncmp(options, "font:", 5))
options++;
}
if (*options != ',')
- return 1;
+ return 0;
options++;
} else
- return 1;
+ return 0;
}
if (!strncmp(options, "map:", 4)) {
con2fb_map_boot[i] =
(options[j++]-'0') % FB_MAX;
}
- return 1;
+ return 0;
}
if (!strncmp(options, "vc:", 3)) {
rotate = 0;
}
}
- return 1;
+ return 0;
}
__setup("fbcon=", fb_console_setup);
{
int i, retval = 0;
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (con2fb_map[i] == idx)
retval = 1;
}
{
int i, retval = 0;
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (con2fb_map[i] != -1)
retval = 1;
}
err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
fbcon_is_default);
-
if (err) {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
con2fb_map[i] = -1;
if (oldidx == newidx)
return 0;
- if (!info || fbcon_has_exited)
- return -EINVAL;
+ if (!info)
+ err = -EINVAL;
if (!err && !search_for_mapped_con()) {
info_idx = newidx;
con2fb_init_display(vc, info, unit, show_logo);
}
- if (!search_fb_in_map(info_idx))
- info_idx = newidx;
-
release_console_sem();
return err;
}
#endif /* CONFIG_MAC */
fbcon_add_cursor_timer(info);
- fbcon_has_exited = 0;
return display_desc;
}
/* If we are not the first console on this
fb, copy the font from that console */
- t = &fb_display[fg_console];
- if (!p->fontdata) {
- if (t->fontdata) {
- struct vc_data *fvc = vc_cons[fg_console].d;
-
- vc->vc_font.data = (void *)(p->fontdata =
- fvc->vc_font.data);
- vc->vc_font.width = fvc->vc_font.width;
- vc->vc_font.height = fvc->vc_font.height;
- p->userfont = t->userfont;
-
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
- } else {
- const struct font_desc *font = NULL;
-
- if (!fontname[0] || !(font = find_font(fontname)))
- font = get_default_font(info->var.xres,
- info->var.yres);
- vc->vc_font.width = font->width;
- vc->vc_font.height = font->height;
- vc->vc_font.data = (void *)(p->fontdata = font->data);
- vc->vc_font.charcount = 256; /* FIXME Need to
- support more fonts */
- }
+ t = &fb_display[svc->vc_num];
+ if (!vc->vc_font.data) {
+ vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
+ vc->vc_font.width = (*default_mode)->vc_font.width;
+ vc->vc_font.height = (*default_mode)->vc_font.height;
+ p->userfont = t->userfont;
+ if (p->userfont)
+ REFCOUNT(p->fontdata)++;
}
-
if (p->userfont)
charcnt = FNTCHARCNT(p->fontdata);
-
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
set_blitting_type(vc, info);
}
- ops->p = &fb_display[fg_console];
-}
-
-static void fbcon_free_font(struct display *p)
-{
- if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
- kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
- p->fontdata = NULL;
- p->userfont = 0;
}
static void fbcon_deinit(struct vc_data *vc)
{
struct display *p = &fb_display[vc->vc_num];
- struct fb_info *info;
- struct fbcon_ops *ops;
- int idx;
+ if (info_idx != -1)
+ return;
fbcon_free_font(p);
- idx = con2fb_map[vc->vc_num];
-
- if (idx == -1)
- goto finished;
-
- info = registered_fb[idx];
-
- if (!info)
- goto finished;
-
- ops = info->fbcon_par;
-
- if (!ops)
- goto finished;
-
- if (CON_IS_VISIBLE(vc))
- fbcon_del_cursor_timer(info);
-
- ops->flags &= ~FBCON_FLAGS_INIT;
-finished:
-
- if (!con_is_bound(&fb_con))
- fbcon_exit();
-
- return;
}
/* ====================================================================== */
fbcon_redraw_move(vc, p, 0, t, count);
ypan_up_redraw(vc, t, count);
if (vc->vc_rows - b > 0)
- fbcon_redraw_move(vc, p, b,
+ fbcon_redraw_move(vc, p, b - count,
vc->vc_rows - b, b);
} else
fbcon_redraw_move(vc, p, t + count, b - t - count, t);
if (info->fbops->fb_set_par)
info->fbops->fb_set_par(info);
- if (old_info != info)
+ if (old_info != info) {
fbcon_del_cursor_timer(old_info);
+ fbcon_add_cursor_timer(info);
+ }
}
- fbcon_add_cursor_timer(info);
set_blitting_type(vc, info);
ops->cursor_reset = 1;
return 0;
}
+static void fbcon_free_font(struct display *p)
+{
+ if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+ kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
+ p->fontdata = NULL;
+ p->userfont = 0;
+}
+
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
{
u8 *fontdata = vc->vc_font.data;
FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
struct vc_data *tmp = vc_cons[i].d;
if (fb_display[i].userfont &&
scr_memcpyw((u16 *) q, (u16 *) p,
vc->vc_size_row);
}
- softback_in = softback_curr = p;
+ softback_in = p;
update_region(vc, vc->vc_origin,
logo_lines * vc->vc_cols);
}
if (!ops || ops->currcon < 0)
return;
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
registered_fb[con2fb_map[i]] != info)
return found;
}
-static int fbcon_fb_unregistered(int idx)
-{
- int i;
-
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
- if (con2fb_map[i] == idx)
- con2fb_map[i] = -1;
- }
-
- if (idx == info_idx) {
- info_idx = -1;
-
- for (i = 0; i < FB_MAX; i++) {
- if (registered_fb[i] != NULL) {
- info_idx = i;
- break;
- }
- }
- }
-
- if (info_idx != -1) {
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
- if (con2fb_map[i] == -1)
- con2fb_map[i] = info_idx;
- }
- }
-
- if (!num_registered_fb)
- unregister_con_driver(&fb_con);
-
- return 0;
-}
-
static int fbcon_fb_registered(int idx)
{
int ret = 0, i;
if (info_idx == -1) {
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (con2fb_map_boot[i] == idx) {
info_idx = idx;
break;
}
}
-
if (info_idx != -1)
ret = fbcon_takeover(1);
} else {
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
- if (con2fb_map_boot[i] == idx &&
- con2fb_map[i] == -1)
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (con2fb_map_boot[i] == idx)
set_con2fb_map(i, idx, 0);
}
}
struct fb_var_screeninfo var;
struct fb_videomode *mode;
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (registered_fb[con2fb_map[i]] != info)
continue;
if (!fb_display[i].mode)
struct fb_con2fbmap *con2fb;
int ret = 0;
- /*
- * ignore all events except driver registration and deregistration
- * if fbcon is not active
- */
- if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
- action == FB_EVENT_FB_UNREGISTERED))
- goto done;
-
switch(action) {
case FB_EVENT_SUSPEND:
fbcon_suspended(info);
case FB_EVENT_FB_REGISTERED:
ret = fbcon_fb_registered(info->node);
break;
- case FB_EVENT_FB_UNREGISTERED:
- ret = fbcon_fb_unregistered(info->node);
- break;
case FB_EVENT_SET_CONSOLE_MAP:
con2fb = event->data;
ret = set_con2fb_map(con2fb->console - 1,
case FB_EVENT_NEW_MODELIST:
fbcon_new_modelist(info);
break;
+ case FB_EVENT_SET_CON_ROTATE:
+ fbcon_rotate(info, *(int *)event->data);
+ break;
+ case FB_EVENT_GET_CON_ROTATE:
+ ret = fbcon_get_rotate(info);
+ break;
+ case FB_EVENT_SET_CON_ROTATE_ALL:
+ fbcon_rotate_all(info, *(int *)event->data);
}
-done:
return ret;
}
.notifier_call = fbcon_event_notify,
};
-static ssize_t store_rotate(struct class_device *class_device,
- const char *buf, size_t count)
-{
- struct fb_info *info;
- int rotate, idx;
- char **last = NULL;
-
- if (fbcon_has_exited)
- return count;
-
- acquire_console_sem();
- idx = con2fb_map[fg_console];
-
- if (idx == -1 || registered_fb[idx] == NULL)
- goto err;
-
- info = registered_fb[idx];
- rotate = simple_strtoul(buf, last, 0);
- fbcon_rotate(info, rotate);
-err:
- release_console_sem();
- return count;
-}
-
-static ssize_t store_rotate_all(struct class_device *class_device,
- const char *buf, size_t count)
-{
- struct fb_info *info;
- int rotate, idx;
- char **last = NULL;
-
- if (fbcon_has_exited)
- return count;
-
- acquire_console_sem();
- idx = con2fb_map[fg_console];
-
- if (idx == -1 || registered_fb[idx] == NULL)
- goto err;
-
- info = registered_fb[idx];
- rotate = simple_strtoul(buf, last, 0);
- fbcon_rotate_all(info, rotate);
-err:
- release_console_sem();
- return count;
-}
-
-static ssize_t show_rotate(struct class_device *class_device, char *buf)
+static int __init fb_console_init(void)
{
- struct fb_info *info;
- int rotate = 0, idx;
-
- if (fbcon_has_exited)
- return 0;
+ int i;
acquire_console_sem();
- idx = con2fb_map[fg_console];
-
- if (idx == -1 || registered_fb[idx] == NULL)
- goto err;
-
- info = registered_fb[idx];
- rotate = fbcon_get_rotate(info);
-err:
+ fb_register_client(&fbcon_event_notifier);
release_console_sem();
- return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
-}
-
-static struct class_device_attribute class_device_attrs[] = {
- __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
- __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
-};
-
-static int fbcon_init_class_device(void)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_create_file(fbcon_class_device,
- &class_device_attrs[i]);
- return 0;
-}
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ con2fb_map[i] = -1;
-static void fbcon_start(void)
-{
if (num_registered_fb) {
- int i;
-
- acquire_console_sem();
-
for (i = 0; i < FB_MAX; i++) {
if (registered_fb[i] != NULL) {
info_idx = i;
break;
}
}
-
- release_console_sem();
fbcon_takeover(0);
}
-}
-
-static void fbcon_exit(void)
-{
- struct fb_info *info;
- int i, j, mapped;
-
- if (fbcon_has_exited)
- return;
-
-#ifdef CONFIG_ATARI
- free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
-#endif
-#ifdef CONFIG_MAC
- if (MACH_IS_MAC && vbl_detected)
- free_irq(IRQ_MAC_VBL, fbcon_vbl_handler);
-#endif
-
- kfree((void *)softback_buf);
- softback_buf = 0UL;
-
- for (i = 0; i < FB_MAX; i++) {
- mapped = 0;
- info = registered_fb[i];
-
- if (info == NULL)
- continue;
-
- for (j = first_fb_vc; j <= last_fb_vc; j++) {
- if (con2fb_map[j] == i)
- mapped = 1;
- }
-
- if (mapped) {
- if (info->fbops->fb_release)
- info->fbops->fb_release(info, 0);
- module_put(info->fbops->owner);
-
- if (info->fbcon_par) {
- struct fbcon_ops *ops = info->fbcon_par;
-
- fbcon_del_cursor_timer(info);
- kfree(ops->cursor_src);
- kfree(info->fbcon_par);
- info->fbcon_par = NULL;
- }
-
- if (info->queue.func == fb_flashcursor)
- info->queue.func = NULL;
- }
- }
-
- fbcon_has_exited = 1;
-}
-static int __init fb_console_init(void)
-{
- int i;
-
- acquire_console_sem();
- fb_register_client(&fbcon_event_notifier);
- fbcon_class_device =
- class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon");
-
- if (IS_ERR(fbcon_class_device)) {
- printk(KERN_WARNING "Unable to create class_device "
- "for fbcon; errno = %ld\n",
- PTR_ERR(fbcon_class_device));
- fbcon_class_device = NULL;
- } else
- fbcon_init_class_device();
-
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- con2fb_map[i] = -1;
-
- release_console_sem();
- fbcon_start();
return 0;
}
#ifdef MODULE
-static void __exit fbcon_deinit_class_device(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_remove_file(fbcon_class_device,
- &class_device_attrs[i]);
-}
-
static void __exit fb_console_exit(void)
{
acquire_console_sem();
fb_unregister_client(&fbcon_event_notifier);
- fbcon_deinit_class_device();
- class_device_destroy(fb_class, MKDEV(0, 0));
- fbcon_exit();
release_console_sem();
- unregister_con_driver(&fb_con);
+ give_up_console(&fb_con);
}
module_exit(fb_console_exit);