Commit 7fbf08c2 authored by Antonino Daplas's avatar Antonino Daplas Committed by Linus Torvalds

[PATCH] Video Mode Handling - Delete entries from mode list

This is optional but applying it should enhance fbdev functionality.

The patch allows removal of entries to the mode list.  This is done by setting
the var->activate field to FB_ACTIVATE_INV_MODE.  Only modes that are not in
use by any of the console or by the current var will be deleted.
Signed-off-by: default avatarAntonino Daplas <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ef49e03a
...@@ -2671,10 +2671,39 @@ static void fbcon_modechanged(struct fb_info *info) ...@@ -2671,10 +2671,39 @@ static void fbcon_modechanged(struct fb_info *info)
} }
} }
static void fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode)
{
struct fb_info *fb_info;
struct display *p;
int i, j, found = 0;
/* before deletion, ensure that mode is not in use */
for (i = first_fb_vc; i <= last_fb_vc; i++) {
j = (int) con2fb_map[i];
if (j == -1)
continue;
fb_info = registered_fb[j];
if (fb_info != info)
continue;
p = &fb_display[i];
if (!p || !p->mode)
continue;
if (fb_mode_is_equal(p->mode, mode)) {
found = 1;
break;
}
}
if (!found)
fb_delete_videomode(mode, &info->monspecs.modelist);
}
static int fbcon_event_notify(struct notifier_block *self, static int fbcon_event_notify(struct notifier_block *self,
unsigned long action, void *data) unsigned long action, void *data)
{ {
struct fb_info *info = (struct fb_info *) data; struct fb_event *event = (struct fb_event *) data;
struct fb_info *info = event->info;
struct fb_videomode *mode;
switch(action) { switch(action) {
case FB_EVENT_SUSPEND: case FB_EVENT_SUSPEND:
...@@ -2686,6 +2715,10 @@ static int fbcon_event_notify(struct notifier_block *self, ...@@ -2686,6 +2715,10 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_MODE_CHANGE: case FB_EVENT_MODE_CHANGE:
fbcon_modechanged(info); fbcon_modechanged(info);
break; break;
case FB_EVENT_MODE_DELETE:
mode = (struct fb_videomode *) event->data;
fbcon_mode_deleted(info, mode);
break;
} }
return 0; return 0;
......
...@@ -1087,6 +1087,22 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -1087,6 +1087,22 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{ {
int err; int err;
if (var->activate & FB_ACTIVATE_INV_MODE) {
struct fb_videomode mode1, mode2;
struct fb_event event;
fb_var_to_videomode(&mode1, var);
fb_var_to_videomode(&mode2, &info->var);
/* make sure we don't delete the videomode of current var */
if (fb_mode_is_equal(&mode1, &mode2))
return -EINVAL;
event.info = info;
event.data = &mode1;
notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_DELETE,
&event);
return 0;
}
if ((var->activate & FB_ACTIVATE_FORCE) || if ((var->activate & FB_ACTIVATE_FORCE) ||
memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
if (!info->fbops->fb_check_var) { if (!info->fbops->fb_check_var) {
...@@ -1112,9 +1128,12 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -1112,9 +1128,12 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_add_videomode(&mode, &info->monspecs.modelist); fb_add_videomode(&mode, &info->monspecs.modelist);
if (info->flags & FBINFO_MISC_MODECHANGEUSER) { if (info->flags & FBINFO_MISC_MODECHANGEUSER) {
struct fb_event event;
info->flags &= ~FBINFO_MISC_MODECHANGEUSER; info->flags &= ~FBINFO_MISC_MODECHANGEUSER;
event.info = info;
notifier_call_chain(&fb_notifier_list, notifier_call_chain(&fb_notifier_list,
FB_EVENT_MODE_CHANGE, info); FB_EVENT_MODE_CHANGE, &event);
} }
} }
} }
...@@ -1524,12 +1543,15 @@ int fb_unregister_client(struct notifier_block *nb) ...@@ -1524,12 +1543,15 @@ int fb_unregister_client(struct notifier_block *nb)
*/ */
void fb_set_suspend(struct fb_info *info, int state) void fb_set_suspend(struct fb_info *info, int state)
{ {
struct fb_event event;
event.info = info;
if (state) { if (state) {
notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, info); notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event);
info->state = FBINFO_STATE_SUSPENDED; info->state = FBINFO_STATE_SUSPENDED;
} else { } else {
info->state = FBINFO_STATE_RUNNING; info->state = FBINFO_STATE_RUNNING;
notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, info); notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event);
} }
} }
......
...@@ -159,6 +159,7 @@ struct fb_bitfield { ...@@ -159,6 +159,7 @@ struct fb_bitfield {
#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ #define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */
#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ #define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */
#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ #define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/
#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */
#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ #define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */
...@@ -449,6 +450,14 @@ struct fb_cursor_user { ...@@ -449,6 +450,14 @@ struct fb_cursor_user {
* if you own it * if you own it
*/ */
#define FB_EVENT_RESUME 0x03 #define FB_EVENT_RESUME 0x03
/* An entry from the modelist was removed */
#define FB_EVENT_MODE_DELETE 0x04
struct fb_event {
struct fb_info *info;
void *data;
};
extern int fb_register_client(struct notifier_block *nb); extern int fb_register_client(struct notifier_block *nb);
extern int fb_unregister_client(struct notifier_block *nb); extern int fb_unregister_client(struct notifier_block *nb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment