linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Patch to add mode setting to sysfs
@ 2005-02-16 22:30 Jon Smirl
  2005-02-16 22:47 ` James Simmons
  2005-02-17 13:50 ` Antonino A. Daplas
  0 siblings, 2 replies; 24+ messages in thread
From: Jon Smirl @ 2005-02-16 22:30 UTC (permalink / raw)
  To: fbdev

This is a first pass at adding two new sysfs attributes to
/sys/class/graphics/fb0 for setting modes. There are two attributes:
modes which contains a list of valid modes, and mode which is the
current mode. To switch modes echo one of the entries from the modes
list to the mode attribute.
The D,V,S on the modes represents Detailed, Vesa, Standard from the DDC info.

modes is root writable. It can also be used to set the list of modes.
For example a /etc file could add modes that are not in the monitor's
DDC.

mode is user writable. PAM would set ownership of mode at user login
time. This provides a safe way  for a user to set the mode without
being root. You can only set the mode to one of the modes on the list.

If this code looks good I'll do another pass that adds some more
features and makes it more robust.

-- 
Jon Smirl
jonsmirl@gmail.com


diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-16 17:20:32 -05:00
+++ b/drivers/video/fbmem.c	2005-02-16 17:20:32 -05:00
@@ -1058,7 +1058,6 @@
 register_framebuffer(struct fb_info *fb_info)
 {
 	int i;
-	struct class_device *c;
 	struct fb_event event;
 
 	if (num_registered_fb == FB_MAX)
@@ -1069,13 +1068,15 @@
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
+	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer
%d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+		printk(KERN_WARNING "Unable to create class_device for framebuffer
%d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
diff -Nru a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c	2005-02-16 17:20:32 -05:00
+++ b/drivers/video/fbsysfs.c	2005-02-16 17:20:32 -05:00
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
+#include <linux/console.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -57,6 +58,7 @@
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -71,6 +73,118 @@
 {
 	kfree(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+static int mode_class(char *buf, int flag)
+{
+	if (flag & FB_MODE_IS_DETAILED)
+		return sprintf(buf, "D:");
+	if (flag & FB_MODE_IS_VESA)
+		return sprintf(buf, "V:");
+	if (flag & FB_MODE_IS_STANDARD)
+		return sprintf(buf, "S:");
+	return sprintf(buf, "U:");
+}
+
+static int mode_string(char *buf, const struct fb_videomode *mode)
+{
+	int i = 0;
+	i += mode_class(buf, mode->flag);
+	return i + sprintf(&buf[i], "%dx%d-%d\n", mode->xres, mode->yres,
mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+	
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			fb_videomode_to_var(&var, mode);
+			var.activate |= FB_ACTIVATE_FORCE;
+			var.bits_per_pixel = 32;
+			acquire_console_sem();
+			fb_info->flags |= FBINFO_MISC_USEREVENT;
+			err = fb_set_var(fb_info, &var);
+			fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+			release_console_sem();
+			if (err)
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	int i = count / sizeof(struct fb_videomode);
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	fb_destroy_modelist(&fb_info->modelist);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i, &fb_info->modelist);
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+	
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(&buf[i], mode);
+	}
+	return i;
+}
+
+CLASS_DEVICE_ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode);
+CLASS_DEVICE_ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes);
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	//INIT_LIST_HEAD(&modelist);
+	class_set_devdata(fb_info->class_device, fb_info);
+	class_device_create_file(fb_info->class_device, &class_device_attr_modes);
+	class_device_create_file(fb_info->class_device, &class_device_attr_mode);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	class_device_remove_file(fb_info->class_device, &class_device_attr_modes);
+	class_device_remove_file(fb_info->class_device, &class_device_attr_mode);
+}
+
+
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	2005-02-16 17:20:32 -05:00
+++ b/include/linux/fb.h	2005-02-16 17:20:32 -05:00
@@ -712,8 +712,10 @@
 	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
+	struct fb_videomode *mode;	/* current mode */
 	struct fb_ops *fbops;
 	struct device *device;
+	struct class_device *class_device; /* sysfs per device attrs */
 #ifdef CONFIG_FB_TILEBLITTING
 	struct fb_tile_ops *tileops;    /* Tile Blitting */
 #endif
@@ -830,6 +832,8 @@
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int fb_init_class_device(struct fb_info *fb_info);
+extern void fb_cleanup_class_device(struct fb_info *head);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-16 22:30 Patch to add mode setting to sysfs Jon Smirl
@ 2005-02-16 22:47 ` James Simmons
  2005-02-17  1:28   ` Jon Smirl
  2005-02-17 13:50 ` Antonino A. Daplas
  1 sibling, 1 reply; 24+ messages in thread
From: James Simmons @ 2005-02-16 22:47 UTC (permalink / raw)
  To: Jon Smirl; +Cc: fbdev


Great work!!!! I have been also working on a sysfs patch. We can merge are 
work. I have a few more features I want to add to my sysfs patch. Like 
allowing a driver to pass in special feature to be exported via sysfs.
Here is what I have currently. Eventually [un]register_framebuffer_sysfs
would become apart of framebuffer_alloc. Well I work one some more stuff.


diff -urN -X /home/jsimmons/dontdiff linus-2.6/drivers/video/fbmem.c fbdev-2.6/drivers/video/fbmem.c
--- linus-2.6/drivers/video/fbmem.c	2005-01-24 09:43:47.000000000 -0800
+++ fbdev-2.6/drivers/video/fbmem.c	2005-02-11 12:42:35.000000000 -0800
@@ -1042,8 +1042,6 @@
 #endif
 };
 
-static struct class_simple *fb_class;
-
 /**
  *	register_framebuffer - registers a frame buffer device
  *	@fb_info: frame buffer info structure
@@ -1057,10 +1055,9 @@
 int
 register_framebuffer(struct fb_info *fb_info)
 {
-	int i;
-	struct class_device *c;
 	struct fb_event event;
-
+	int i;
+	
 	if (num_registered_fb == FB_MAX)
 		return -ENXIO;
 	num_registered_fb++;
@@ -1069,13 +1066,8 @@
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
-				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
-		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+	register_framebuffer_sysfs(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
@@ -1134,7 +1126,7 @@
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
-	class_simple_device_remove(MKDEV(FB_MAJOR, i));
+	unregister_framebuffer_sysfs(fb_info);
 	return 0;
 }
 
@@ -1197,11 +1189,7 @@
 	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
 		printk("unable to get major %d for fb devs\n", FB_MAJOR);
 
-	fb_class = class_simple_create(THIS_MODULE, "graphics");
-	if (IS_ERR(fb_class)) {
-		printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
-		fb_class = NULL;
-	}
+	fb_sysfs_init();
 	return 0;
 }
 subsys_initcall(fbmem_init);
diff -urN -X /home/jsimmons/dontdiff linus-2.6/drivers/video/fbsysfs.c fbdev-2.6/drivers/video/fbsysfs.c
--- linus-2.6/drivers/video/fbsysfs.c	2005-02-11 13:37:28.000000000 -0800
+++ fbdev-2.6/drivers/video/fbsysfs.c	2005-02-11 15:04:12.000000000 -0800
@@ -15,9 +15,130 @@
  * are converted to use it a sysfsification will open OOPSable races.
  */
 
+#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/sysfs.h>
 #include <linux/fb.h>
 
+/*
+ * Graphics Class handling
+ */
+#define to_fb_info(class) container_of(class, struct fb_info, class_dev)
+
+static void graphics_class_release(struct class_device *dev)
+{
+	// struct fb_info *info = class_get_devdata(dev);
+	struct fb_info *info = to_fb_info(dev);
+
+	fb_dealloc_cmap(&info->cmap);
+	kfree(info);
+}
+
+struct class graphics_class = {
+	.name		= "graphics",
+	.release	= &graphics_class_release,
+};
+
+int __init fb_sysfs_init(void)
+{
+	return class_register(&graphics_class);
+}
+
+/*
+ * Framebuffer Device handling
+ */
+static ssize_t show_fbdev(struct class_device *dev, char *buf)
+{
+	//struct fb_info *info = class_get_devdata(dev);
+	struct fb_info *info = to_fb_info(dev);
+
+	return sprintf(buf, "%u:%u\n", FB_MAJOR, info->node);
+}
+
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_fbdev, NULL);
+
+static ssize_t show_name(struct class_device *dev, char *buf)
+{
+	struct fb_info *info = to_fb_info(dev);
+
+	return sprintf(buf, "%s\n", info->fix.id);
+}
+
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct class_device_attribute *frame_class_device_attributes[] = {
+	&class_device_attr_dev,
+	&class_device_attr_name,
+};
+
+
+// Mode list handling
+/* generate a read-only statistics attribute */
+static ssize_t show_resolution(struct class_device *dev, char *buf)
+{
+	return 0;
+}
+
+static CLASS_DEVICE_ATTR(mode, S_IRUGO, show_resolution, NULL);
+
+static struct attribute *frame_attrs[] = {
+	&class_device_attr_dev.attr,
+	&class_device_attr_name.attr,
+	NULL
+};
+
+// Register sysfs.
+int register_framebuffer_sysfs(struct fb_info *info)
+{
+	struct attribute_group *modes_group;
+	int rc, size, i;
+
+	snprintf(info->class_dev.class_id, BUS_ID_SIZE, "fb%d", info->node);
+	class_set_devdata(&info->class_dev, info);
+	info->class_dev.class = &graphics_class;
+
+	rc = class_device_register(&info->class_dev);
+	if (rc)
+		return rc;
+	info->class_dev.dev = info->device;
+
+	for (i = 0; i < ARRAY_SIZE(frame_class_device_attributes); i++) {
+		rc = class_device_create_file(&info->class_dev, frame_class_device_attributes[i]);
+		if (unlikely(rc)) {
+			/* Not fatal */
+			printk(KERN_WARNING "Unable to create device file for framebuffer %d\n", info->node);
+		}
+	}
+	info->class_dev.dev = info->device;
+
+	size = sizeof(modes_group) + strlen("modes");
+	modes_group = kmalloc(size, GFP_KERNEL);
+	if (modes_group) {
+		memset(modes_group, 0, size);
+		modes_group->name = (char *)(modes_group + sizeof(modes_group));
+		sprintf(modes_group->name, "modes");
+		modes_group->attrs = frame_attrs;
+		rc = sysfs_create_group(&info->class_dev.kobj, modes_group);
+		if (rc)
+			kfree(modes_group);
+	}
+	return 0;
+}
+
+void unregister_framebuffer_sysfs(struct fb_info *info)
+{
+	int i;
+
+	if (info->class_dev.dev == info->device) {
+		//sysfs_remove_group(&info->class_dev.kobj, &modes_group);
+
+		for (i = 0; i < ARRAY_SIZE(frame_class_device_attributes); i++)
+			class_device_remove_file(&info->class_dev, frame_class_device_attributes[i]);
+		class_device_unregister(&info->class_dev);
+	}
+}
+
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
  *
@@ -47,16 +168,14 @@
 		return NULL;
 	memset(p, 0, fb_info_size + size);
 	info = (struct fb_info *) p;
-
+	info->device = dev;
 	if (size)
 		info->par = p + fb_info_size;
-
-	info->device = dev;
-
 	return info;
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -69,8 +188,8 @@
  */
 void framebuffer_release(struct fb_info *info)
 {
-	kfree(info);
+	unregister_framebuffer_sysfs(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+MODULE_LICENSE("GPL");
diff -urN -X /home/jsimmons/dontdiff linus-2.6/include/linux/fb.h fbdev-2.6/include/linux/fb.h
--- linus-2.6/include/linux/fb.h	2005-02-11 16:57:25.000000000 -0800
+++ fbdev-2.6/include/linux/fb.h	2005-02-11 09:59:33.000000000 -0800
@@ -704,6 +704,7 @@
 struct fb_info {
 	int node;
 	int flags;
+	struct class_device class_dev;	/* Sysfs support */
 	struct fb_var_screeninfo var;	/* Current var */
 	struct fb_fix_screeninfo fix;	/* Current fix */
 	struct fb_monspecs monspecs;	/* Current Monitor specs */
@@ -827,9 +828,22 @@
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
 
+/* drivers/video/fbcmap.c */
+extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
+extern void fb_dealloc_cmap(struct fb_cmap *cmap);
+extern int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to);
+extern int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to);
+extern int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info);
+extern int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *fb_info);
+extern struct fb_cmap *fb_default_cmap(int len);
+extern void fb_invert_cmaps(void);
+
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int register_framebuffer_sysfs(struct fb_info *info);
+extern void unregister_framebuffer_sysfs(struct fb_info *info);
+extern int fb_sysfs_init(void);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0
@@ -861,35 +875,6 @@
 extern void fb_destroy_modedb(struct fb_videomode *modedb);
 
 /* drivers/video/modedb.c */
-#define VESA_MODEDB_SIZE 34
-extern const struct fb_videomode vesa_modes[];
-extern void fb_var_to_videomode(struct fb_videomode *mode,
-				struct fb_var_screeninfo *var);
-extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
-				struct fb_videomode *mode);
-extern int fb_mode_is_equal(struct fb_videomode *mode1,
-			    struct fb_videomode *mode2);
-extern int fb_add_videomode(struct fb_videomode *mode, struct list_head *head);
-extern void fb_delete_videomode(struct fb_videomode *mode,
-				struct list_head *head);
-extern struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var,
-					  struct list_head *head);
-extern struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
-					      struct list_head *head);
-extern void fb_destroy_modelist(struct list_head *head);
-extern void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
-				     struct list_head *head);
-
-/* drivers/video/fbcmap.c */
-extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-extern void fb_dealloc_cmap(struct fb_cmap *cmap);
-extern int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to);
-extern int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to);
-extern int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info);
-extern int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *fb_info);
-extern struct fb_cmap *fb_default_cmap(int len);
-extern void fb_invert_cmaps(void);
-
 struct fb_videomode {
 	const char *name;	/* optional */
 	u32 refresh;		/* optional */
@@ -912,6 +897,25 @@
 	struct fb_videomode mode;
 };
 
+#define VESA_MODEDB_SIZE 34
+extern const struct fb_videomode vesa_modes[];
+
+extern void fb_var_to_videomode(struct fb_videomode *mode,
+				struct fb_var_screeninfo *var);
+extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
+				struct fb_videomode *mode);
+extern int fb_mode_is_equal(struct fb_videomode *mode1,
+			    struct fb_videomode *mode2);
+extern int fb_add_videomode(struct fb_videomode *mode, struct list_head *head);
+extern void fb_delete_videomode(struct fb_videomode *mode,
+				struct list_head *head);
+extern struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var,
+					  struct list_head *head);
+extern struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
+					      struct list_head *head);
+extern void fb_destroy_modelist(struct list_head *head);
+extern void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
+				     struct list_head *head);
 extern int fb_find_mode(struct fb_var_screeninfo *var,
 			struct fb_info *info, const char *mode_option,
 			const struct fb_videomode *db,


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-16 22:47 ` James Simmons
@ 2005-02-17  1:28   ` Jon Smirl
  0 siblings, 0 replies; 24+ messages in thread
From: Jon Smirl @ 2005-02-17  1:28 UTC (permalink / raw)
  To: James Simmons; +Cc: fbdev

I applied your patch, it makes a new directory,
sys/class/graphics/fb0/modes with two entries dev and name. What is
your mechanism for displaying the list of modes and setting a new one?

Note that you can continue to use class_simple as
class_simple_device_add returns the class_device for the new device.

Give my patch a try, cat 'modes' and you you can see the list of
modes. Echo one to 'mode' and it will set the new mode. The mode set
works without being root.

-- 
Jon Smirl
jonsmirl@gmail.com


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-16 22:30 Patch to add mode setting to sysfs Jon Smirl
  2005-02-16 22:47 ` James Simmons
@ 2005-02-17 13:50 ` Antonino A. Daplas
  2005-02-17 20:49   ` Jon Smirl
  1 sibling, 1 reply; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-17 13:50 UTC (permalink / raw)
  To: linux-fbdev-devel, Jon Smirl

On Thursday 17 February 2005 06:30, Jon Smirl wrote:
> This is a first pass at adding two new sysfs attributes to
> /sys/class/graphics/fb0 for setting modes. There are two attributes:
> modes which contains a list of valid modes, and mode which is the
> current mode. To switch modes echo one of the entries from the modes
> list to the mode attribute.
> The D,V,S on the modes represents Detailed, Vesa, Standard from the DDC
> info.
>
> modes is root writable. It can also be used to set the list of modes.
> For example a /etc file could add modes that are not in the monitor's
> DDC.
>
> mode is user writable. PAM would set ownership of mode at user login
> time. This provides a safe way  for a user to set the mode without
> being root. You can only set the mode to one of the modes on the list.
>
> If this code looks good I'll do another pass that adds some more
> features and makes it more robust.

Looks very interesting, and I will try it soon.  A few comments:

+                       fb_videomode_to_var(&var, mode);
+                       var.activate |= FB_ACTIVATE_FORCE;
+                       var.bits_per_pixel = 32;

Instead of hardcoding some of the fields in var, why not
copy it from the current var?  Ie:

var = info->var;
fb_videomode_to_var(&var, mode);

Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-17 13:50 ` Antonino A. Daplas
@ 2005-02-17 20:49   ` Jon Smirl
  2005-02-17 22:13     ` James Simmons
  2005-02-18  0:04     ` Antonino A. Daplas
  0 siblings, 2 replies; 24+ messages in thread
From: Jon Smirl @ 2005-02-17 20:49 UTC (permalink / raw)
  To: adaplas, James Simmons; +Cc: linux-fbdev-devel

On Thu, 17 Feb 2005 21:50:16 +0800, Antonino A. Daplas
<adaplas@hotpop.com> wrote:
> Instead of hardcoding some of the fields in var, why not
> copy it from the current var?  Ie:
> 
> var = info->var;
> fb_videomode_to_var(&var, mode);

I added this change, plus more robust error handing. Add attributes
for virtual resolution and bpp.

I also fixed fb so that it works as module.

-- 
Jon Smirl
jonsmirl@gmail.com



diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig
--- a/drivers/video/Kconfig	2005-02-17 15:46:50 -05:00
+++ b/drivers/video/Kconfig	2005-02-17 15:46:50 -05:00
@@ -5,7 +5,7 @@
 menu "Graphics support"
 
 config FB
-	bool "Support for frame buffer devices"
+	tristate "Support for frame buffer devices"
 	---help---
 	  The frame buffer device provides an abstraction for the graphics
 	  hardware. It represents the frame buffer of some video hardware and
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	2005-02-17 15:46:50 -05:00
+++ b/drivers/video/Makefile	2005-02-17 15:46:50 -05:00
@@ -8,11 +8,13 @@
 obj-$(CONFIG_LOGO)		  += logo/
 obj-$(CONFIG_SYSFS)		  += backlight/
 
-obj-$(CONFIG_FB)                  += fbmem.o fbmon.o fbcmap.o
fbsysfs.o modedb.o softcursor.o
+obj-$(CONFIG_FB)                  += fb.o
+fb-y                              := fbmem.o fbmon.o fbcmap.o
fbsysfs.o modedb.o softcursor.o
 # Only include macmodes.o if we have FB support and are PPC
-ifeq ($(CONFIG_FB),y)
-obj-$(CONFIG_PPC)                 += macmodes.o
+ifneq ($(CONFIG_FB),n)
+fb-$(CONFIG_PPC)                  += macmodes.o
 endif
+fb-objs                           := $(fb-y)
 
 # Hardware specific drivers go first
 obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-17 15:46:50 -05:00
+++ b/drivers/video/fbmem.c	2005-02-17 15:46:50 -05:00
@@ -1058,7 +1058,6 @@
 register_framebuffer(struct fb_info *fb_info)
 {
 	int i;
-	struct class_device *c;
 	struct fb_event event;
 
 	if (num_registered_fb == FB_MAX)
@@ -1069,13 +1068,15 @@
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
+	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer
%d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+		printk(KERN_WARNING "Unable to create class_device for framebuffer
%d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
@@ -1134,6 +1135,7 @@
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
+	fb_cleanup_class_device(fb_info);
 	class_simple_device_remove(MKDEV(FB_MAJOR, i));
 	return 0;
 }
@@ -1204,7 +1206,20 @@
 	}
 	return 0;
 }
+#ifdef MODULE
+module_init(fbmem_init);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer base");
+
+void __exit
+fbmem_exit(void)
+{
+	class_simple_destroy(fb_class);
+}
+module_exit(fbmem_exit);
+#else
 subsys_initcall(fbmem_init);
+#endif
 
 static char *video_options[FB_MAX];
 static int ofonly;
diff -Nru a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c	2005-02-17 15:46:50 -05:00
+++ b/drivers/video/fbsysfs.c	2005-02-17 15:46:50 -05:00
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
+#include <linux/console.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -57,6 +58,7 @@
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -71,6 +73,187 @@
 {
 	kfree(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+	int err;
+	
+	var->activate |= FB_ACTIVATE_FORCE;
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_set_var(fb_info, var);
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err)
+		return err;
+	return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset, const struct
fb_videomode *mode)
+{
+	char m = 'U';
+	if (mode->flag & FB_MODE_IS_DETAILED)
+		m = 'D';
+	if (mode->flag & FB_MODE_IS_VESA)
+		m = 'V';
+	if (mode->flag & FB_MODE_IS_STANDARD)
+		m = 'S';
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n",
m, mode->xres, mode->yres, mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, 0, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			var = fb_info->var;
+			fb_videomode_to_var(&var, mode);
+			if ((err = activate(fb_info, &var)))
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	int i = count / sizeof(struct fb_videomode);
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	fb_destroy_modelist(&fb_info->modelist);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i, &fb_info->modelist);
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	unsigned int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(buf, i, mode);
+	}
+	return i;
+}
+
+static ssize_t store_bpp(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char ** last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.bits_per_pixel = simple_strtoul(buf, last, 0);
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_bpp(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_virtual(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xres_virtual = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yres_virtual = simple_strtoul(last, &last, 0);
+	printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual, var.yres_virtual);
+	
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_virtual(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n",
fb_info->var.xres_virtual, fb_info->var.xres_virtual);
+}
+
+static ssize_t store_cmap(struct class_device *class_device, const
char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cmap(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+CLASS_DEVICE_ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode);
+CLASS_DEVICE_ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes);
+CLASS_DEVICE_ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp);
+CLASS_DEVICE_ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual);
+CLASS_DEVICE_ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap);
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	class_set_devdata(fb_info->class_device, fb_info);
+	class_device_create_file(fb_info->class_device, &class_device_attr_modes);
+	class_device_create_file(fb_info->class_device, &class_device_attr_mode);
+	class_device_create_file(fb_info->class_device,
&class_device_attr_bits_per_pixel);
+	class_device_create_file(fb_info->class_device,
&class_device_attr_virtual_size);
+	class_device_create_file(fb_info->class_device, &class_device_attr_color_map);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	class_device_remove_file(fb_info->class_device, &class_device_attr_modes);
+	class_device_remove_file(fb_info->class_device, &class_device_attr_mode);
+	class_device_remove_file(fb_info->class_device,
&class_device_attr_bits_per_pixel);
+	class_device_remove_file(fb_info->class_device,
&class_device_attr_virtual_size);
+	class_device_remove_file(fb_info->class_device, &class_device_attr_color_map);
+}
+
+
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	2005-02-17 15:46:50 -05:00
+++ b/include/linux/fb.h	2005-02-17 15:46:50 -05:00
@@ -712,8 +712,10 @@
 	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
+	struct fb_videomode *mode;	/* current mode */
 	struct fb_ops *fbops;
 	struct device *device;
+	struct class_device *class_device; /* sysfs per device attrs */
 #ifdef CONFIG_FB_TILEBLITTING
 	struct fb_tile_ops *tileops;    /* Tile Blitting */
 #endif
@@ -830,6 +832,8 @@
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int fb_init_class_device(struct fb_info *fb_info);
+extern void fb_cleanup_class_device(struct fb_info *head);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-17 20:49   ` Jon Smirl
@ 2005-02-17 22:13     ` James Simmons
  2005-02-18  0:04     ` Antonino A. Daplas
  1 sibling, 0 replies; 24+ messages in thread
From: James Simmons @ 2005-02-17 22:13 UTC (permalink / raw)
  To: Jon Smirl; +Cc: adaplas, James Simmons, linux-fbdev-devel



> On Thu, 17 Feb 2005 21:50:16 +0800, Antonino A. Daplas
> <adaplas@hotpop.com> wrote:
> > Instead of hardcoding some of the fields in var, why not
> > copy it from the current var?  Ie:
> > 
> > var = info->var;
> > fb_videomode_to_var(&var, mode);
> 
> I added this change, plus more robust error handing. Add attributes
> for virtual resolution and bpp.
> 
> I also fixed fb so that it works as module.

Seperate the make fbdev modular into another patch. Also I have a feeling 
that will open a whole new can of worms. Also please create something 
like

static struct attribute *frame_attrs[] = {
	&class_device_attr_dev.attr,
	&class_device_attr_name.attr,
	NULL
};

and do 

for (i = 0; i < ARRAY_SIZE(frame_class_device_attributes); i++) {
               rc = class_device_create_file(&info->class_dev, frame_class_device_attributes[i]);
               if (unlikely(rc)) {
                       /* Not fatal */
                       printk(KERN_WARNING "Unable to create device file  for framebuffer %d\n", info->node);
             }
       }


Did you see me email with my ideas about the sysfs structure?



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-17 20:49   ` Jon Smirl
  2005-02-17 22:13     ` James Simmons
@ 2005-02-18  0:04     ` Antonino A. Daplas
  2005-02-18  0:39       ` Jon Smirl
                         ` (2 more replies)
  1 sibling, 3 replies; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-18  0:04 UTC (permalink / raw)
  To: Jon Smirl, adaplas, James Simmons; +Cc: linux-fbdev-devel

On Friday 18 February 2005 04:49, Jon Smirl wrote:
> On Thu, 17 Feb 2005 21:50:16 +0800, Antonino A. Daplas
>
> <adaplas@hotpop.com> wrote:
> > Instead of hardcoding some of the fields in var, why not
> > copy it from the current var?  Ie:
> >
> > var = info->var;
> > fb_videomode_to_var(&var, mode);
>
> I added this change, plus more robust error handing. Add attributes
> for virtual resolution and bpp.
>
> I also fixed fb so that it works as module.

If possible, separate the sysfs patch from making fbcore as module.

+static ssize_t store_modes(struct class_device *class_device, const
char * buf, size_t count)
+{
+       struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+       int i = count / sizeof(struct fb_videomode);
+       if (i * sizeof(struct fb_videomode) != count)
+               return -EINVAL;
+
+       fb_destroy_modelist(&fb_info->modelist);

This is dangerous.  For one, if the mode in info->var does not match any of
the entries in the modelist, you can get a screwed up display.  Secondly,
fbcon refers to info->modelist to store settings for each console.  Thus
it is better to check first if the mode in the modelist is currently in use.

A safer way is to loop through each entries of the old modelist, call 
fb_set_var() with the FB_ACTIVATE_INV_MODE set in var->activate. This
process will safely remove each mode from the modelist.  Not all entries
will be deleted of course. After that, loop through each entries of the new
modedb array, and use fb_add_videomode() to add each entry to the modelist.

Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  0:04     ` Antonino A. Daplas
@ 2005-02-18  0:39       ` Jon Smirl
  2005-02-21 18:37         ` James Simmons
  2005-02-18  2:59       ` Jon Smirl
  2005-02-18  7:27       ` Jon Smirl
  2 siblings, 1 reply; 24+ messages in thread
From: Jon Smirl @ 2005-02-18  0:39 UTC (permalink / raw)
  To: adaplas; +Cc: linux-fbdev-devel, James Simmons

On Fri, 18 Feb 2005 08:04:46 +0800, Antonino A. Daplas
<adaplas@hotpop.com> wrote:
> If possible, separate the sysfs patch from making fbcore as module.

Split for making fbcore into a module. It's pretty minor.

-- 
Jon Smirl
jonsmirl@gmail.com


diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig
--- a/drivers/video/Kconfig	2005-02-17 19:11:37 -05:00
+++ b/drivers/video/Kconfig	2005-02-17 19:11:37 -05:00
@@ -5,7 +5,7 @@
 menu "Graphics support"
 
 config FB
-	bool "Support for frame buffer devices"
+	tristate "Support for frame buffer devices"
 	---help---
 	  The frame buffer device provides an abstraction for the graphics
 	  hardware. It represents the frame buffer of some video hardware and
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	2005-02-17 19:11:37 -05:00
+++ b/drivers/video/Makefile	2005-02-17 19:11:37 -05:00
@@ -8,11 +8,13 @@
 obj-$(CONFIG_LOGO)		  += logo/
 obj-$(CONFIG_SYSFS)		  += backlight/
 
-obj-$(CONFIG_FB)                  += fbmem.o fbmon.o fbcmap.o
fbsysfs.o modedb.o softcursor.o
+obj-$(CONFIG_FB)                  += fb.o
+fb-y                              := fbmem.o fbmon.o fbcmap.o
fbsysfs.o modedb.o softcursor.o
 # Only include macmodes.o if we have FB support and are PPC
-ifeq ($(CONFIG_FB),y)
-obj-$(CONFIG_PPC)                 += macmodes.o
+ifneq ($(CONFIG_FB),n)
+fb-$(CONFIG_PPC)                  += macmodes.o
 endif
+fb-objs                           := $(fb-y)
 
 # Hardware specific drivers go first
 obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-17 19:11:37 -05:00
+++ b/drivers/video/fbmem.c	2005-02-17 19:11:37 -05:00
@@ -1204,7 +1204,22 @@
 	}
 	return 0;
 }
+
+void __exit
+fbmem_exit(void)
+{
+	class_simple_destroy(fb_class);
+}
+
+#ifdef MODULE
+module_init(fbmem_init);
+module_exit(fbmem_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer base");
+#else
 subsys_initcall(fbmem_init);
+subsys_exitcall(fbmem_exit);
+#endif
 
 static char *video_options[FB_MAX];
 static int ofonly;


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  0:04     ` Antonino A. Daplas
  2005-02-18  0:39       ` Jon Smirl
@ 2005-02-18  2:59       ` Jon Smirl
  2005-02-18  7:31         ` Antonino A. Daplas
  2005-02-18  7:27       ` Jon Smirl
  2 siblings, 1 reply; 24+ messages in thread
From: Jon Smirl @ 2005-02-18  2:59 UTC (permalink / raw)
  To: adaplas; +Cc: linux-fbdev-devel, James Simmons

On Fri, 18 Feb 2005 08:04:46 +0800, Antonino A. Daplas
<adaplas@hotpop.com> wrote:
> This is dangerous.  For one, if the mode in info->var does not match any of
> the entries in the modelist, you can get a screwed up display.  Secondly,
> fbcon refers to info->modelist to store settings for each console.  Thus
> it is better to check first if the mode in the modelist is currently in use.
> 
> A safer way is to loop through each entries of the old modelist, call
> fb_set_var() with the FB_ACTIVATE_INV_MODE set in var->activate. This
> process will safely remove each mode from the modelist.  Not all entries
> will be deleted of course. After that, loop through each entries of the new
> modedb array, and use fb_add_videomode() to add each entry to the modelist.

Radeon hardware has an interrupt that is not hooked up in radeonfb
that can tell if the monitor has been switched. Hook a radeon to a KVM
switch and flip the switch. We should get an interrupt. Use the
interrupt to trigger a hotplug event. Hotplug event will set a new
list of modes into radeonfb. All of the old modes have to be deleted,
they probably don't exist in the new monitor.

At this point fbcon needs to get a modelist change event. It can then
find_mode() to find a new mode that is close to what it was using. So
the problem seems to be that disp->mode holds a pointer to the mode
instead of a copy of the mode. I'll try changing this to a copy. Does
fbcon really need to know the entire mode structure or could it work
with just the resolution?

I'd feel more comfortable if fbcon used a well defined interface to
fbdev instead of having access to all of fbdev's internal structures.
I tried modifying fbcon to use DRM but it is completely tied to fbdev.
Anyway, the current code is much better than it was in 2.4.

-- 
Jon Smirl
jonsmirl@gmail.com


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  0:04     ` Antonino A. Daplas
  2005-02-18  0:39       ` Jon Smirl
  2005-02-18  2:59       ` Jon Smirl
@ 2005-02-18  7:27       ` Jon Smirl
  2005-02-18  7:41         ` Antonino A. Daplas
  2005-02-18  7:42         ` Antonino A. Daplas
  2 siblings, 2 replies; 24+ messages in thread
From: Jon Smirl @ 2005-02-18  7:27 UTC (permalink / raw)
  To: adaplas, James Simmons; +Cc: linux-fbdev-devel

Next version of sysfs patch. Fills out more attributes. Feel free to
add code for missing implementations. Modifies fbcon to copy mode
structure instead of taking a reference to it. Modular fbdev is
separate patch. Ultimately we should be able to eliminate the IOCTL
code from fb_core and move it to a compatibility module.

-- 
Jon Smirl
jonsmirl@gmail.com

diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/console/fbcon.c	2005-02-18 02:17:45 -05:00
@@ -681,6 +681,8 @@
 			  struct fb_var_screeninfo *var,
 			  struct fb_info *info)
 {
+	struct fb_videomode *mode;
+
 	disp->xres_virtual = var->xres_virtual;
 	disp->yres_virtual = var->yres_virtual;
 	disp->bits_per_pixel = var->bits_per_pixel;
@@ -693,17 +695,18 @@
 	disp->green = var->green;
 	disp->blue = var->blue;
 	disp->transp = var->transp;
-	disp->mode = fb_match_mode(var, &info->modelist);
-	if (disp->mode == NULL)
+	mode = fb_match_mode(var, &info->modelist);
+	if (mode == NULL)
 		/* This should not happen */
 		return -EINVAL;
+	disp->mode = *mode;
 	return 0;
 }
 
 static void display_to_var(struct fb_var_screeninfo *var,
 			   struct display *disp)
 {
-	fb_videomode_to_var(var, disp->mode);
+	fb_videomode_to_var(var, &disp->mode);
 	var->xres_virtual = disp->xres_virtual;
 	var->yres_virtual = disp->yres_virtual;
 	var->bits_per_pixel = disp->bits_per_pixel;
@@ -2605,9 +2608,9 @@
 		if (fb_info != info)
 			continue;
 		p = &fb_display[i];
-		if (!p || !p->mode)
+		if (!p)
 			continue;
-		if (fb_mode_is_equal(p->mode, mode)) {
+		if (fb_mode_is_equal(&p->mode, mode)) {
 			found = 1;
 			break;
 		}
diff -Nru a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
--- a/drivers/video/console/fbcon.h	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/console/fbcon.h	2005-02-18 02:17:45 -05:00
@@ -45,7 +45,7 @@
     struct fb_bitfield green;
     struct fb_bitfield blue;
     struct fb_bitfield transp;
-    struct fb_videomode *mode;
+    struct fb_videomode mode;
 };
 
 struct fbcon_ops {
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/fbmem.c	2005-02-18 02:17:45 -05:00
@@ -1058,7 +1058,6 @@
 register_framebuffer(struct fb_info *fb_info)
 {
 	int i;
-	struct class_device *c;
 	struct fb_event event;
 
 	if (num_registered_fb == FB_MAX)
@@ -1069,13 +1068,15 @@
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
+	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer
%d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+		printk(KERN_WARNING "Unable to create class_device for framebuffer
%d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
@@ -1134,6 +1135,7 @@
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
+	fb_cleanup_class_device(fb_info);
 	class_simple_device_remove(MKDEV(FB_MAJOR, i));
 	return 0;
 }
diff -Nru a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/fbsysfs.c	2005-02-18 02:17:45 -05:00
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
+#include <linux/console.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -57,6 +58,7 @@
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -71,6 +73,276 @@
 {
 	kfree(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+	int err;
+	
+	var->activate |= FB_ACTIVATE_FORCE;
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_set_var(fb_info, var);
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err)
+		return err;
+	return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset, const struct
fb_videomode *mode)
+{
+	char m = 'U';
+	if (mode->flag & FB_MODE_IS_DETAILED)
+		m = 'D';
+	if (mode->flag & FB_MODE_IS_VESA)
+		m = 'V';
+	if (mode->flag & FB_MODE_IS_STANDARD)
+		m = 'S';
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n",
m, mode->xres, mode->yres, mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, 0, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			var = fb_info->var;
+			fb_videomode_to_var(&var, mode);
+			if ((err = activate(fb_info, &var)))
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	int i = count / sizeof(struct fb_videomode);
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	fb_destroy_modelist(&fb_info->modelist);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i, &fb_info->modelist);
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	unsigned int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(buf, i, mode);
+	}
+	return i;
+}
+
+static ssize_t store_bpp(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char ** last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.bits_per_pixel = simple_strtoul(buf, last, 0);
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_bpp(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_virtual(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xres_virtual = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yres_virtual = simple_strtoul(last, &last, 0);
+	printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual, var.yres_virtual);
+	
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_virtual(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n",
fb_info->var.xres_virtual, fb_info->var.xres_virtual);
+}
+
+static ssize_t store_cmap(struct class_device *class_device, const
char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cmap(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	unsigned int offset = 0, i;
+	
+	if (!fb_info->cmap.red || !fb_info->cmap.blue || fb_info->cmap.green
|| fb_info->cmap.transp)
+		return -EINVAL;
+	
+	for (i = 0; i < fb_info->cmap.len; i++) {
+		offset += snprintf(buf, PAGE_SIZE - offset, "%d,%d,%d,%d,%d\n", i +
fb_info->cmap.start,
+				   fb_info->cmap.red[i], fb_info->cmap.blue[i], fb_info->cmap.green[i], 
+				   fb_info->cmap.transp[i]); 
+	}
+	return offset;
+}
+
+static ssize_t store_blank(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	char *last = NULL;
+	int err;
+
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_blank(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_console(struct class_device *class_device, const
char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_console(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_cursor(struct class_device *class_device, const
char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cursor(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_pan(struct class_device *class_device, const
char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xoffset = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yoffset = simple_strtoul(last, &last, 0);
+	
+	acquire_console_sem();
+	err = fb_pan_display(fb_info, &var);
+	release_console_sem();
+	
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_pan(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
fb_info->var.xoffset);
+}
+
+struct class_device_attribute class_device_attrs[] = {
+	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
+	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
+	__ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
+	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
+	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
+	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
+	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
+};
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+	class_set_devdata(fb_info->class_device, fb_info);
+	
+	for (i = 0; i < sizeof(class_device_attrs)/sizeof(class_device_attrs[0]); i++)
+		class_device_create_file(fb_info->class_device, &class_device_attrs[i]);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(class_device_attrs)/sizeof(class_device_attrs[0]); i++)
+		class_device_remove_file(fb_info->class_device, &class_device_attrs[i]);
+}
+
+
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	2005-02-18 02:17:45 -05:00
+++ b/include/linux/fb.h	2005-02-18 02:17:45 -05:00
@@ -712,8 +712,10 @@
 	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
+	struct fb_videomode *mode;	/* current mode */
 	struct fb_ops *fbops;
 	struct device *device;
+	struct class_device *class_device; /* sysfs per device attrs */
 #ifdef CONFIG_FB_TILEBLITTING
 	struct fb_tile_ops *tileops;    /* Tile Blitting */
 #endif
@@ -830,6 +832,8 @@
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int fb_init_class_device(struct fb_info *fb_info);
+extern void fb_cleanup_class_device(struct fb_info *head);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  2:59       ` Jon Smirl
@ 2005-02-18  7:31         ` Antonino A. Daplas
  2005-02-18  9:42           ` Geert Uytterhoeven
  0 siblings, 1 reply; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-18  7:31 UTC (permalink / raw)
  To: Jon Smirl, adaplas; +Cc: linux-fbdev-devel, James Simmons

On Friday 18 February 2005 10:59, Jon Smirl wrote:
> On Fri, 18 Feb 2005 08:04:46 +0800, Antonino A. Daplas
>
> <adaplas@hotpop.com> wrote:
> > This is dangerous.  For one, if the mode in info->var does not match any
> > of the entries in the modelist, you can get a screwed up display. 
> > Secondly, fbcon refers to info->modelist to store settings for each
> > console.  Thus it is better to check first if the mode in the modelist is
> > currently in use.
> >
> > A safer way is to loop through each entries of the old modelist, call
> > fb_set_var() with the FB_ACTIVATE_INV_MODE set in var->activate. This
> > process will safely remove each mode from the modelist.  Not all entries
> > will be deleted of course. After that, loop through each entries of the
> > new modedb array, and use fb_add_videomode() to add each entry to the
> > modelist.
>
> Radeon hardware has an interrupt that is not hooked up in radeonfb
> that can tell if the monitor has been switched. Hook a radeon to a KVM
> switch and flip the switch. We should get an interrupt. Use the
> interrupt to trigger a hotplug event. Hotplug event will set a new
> list of modes into radeonfb. All of the old modes have to be deleted,
> they probably don't exist in the new monitor.
>

Just trying to point out that destroying the modelist is not entirely safe.

> At this point fbcon needs to get a modelist change event. It can then
> find_mode() to find a new mode that is close to what it was using. So
> the problem seems to be that disp->mode holds a pointer to the mode
> instead of a copy of the mode. I'll try changing this to a copy. Does

Whether it's a copy or a pointer does not matter anyway, because fbcon
still need to resize each console using the new modelist.

> fbcon really need to know the entire mode structure or could it work
> with just the resolution?

fbcon only needs xres, yres, vxres and vyres.  But in order to preserve
the graphics state per console, everything in var is required.

>
> I'd feel more comfortable if fbcon used a well defined interface to
> fbdev instead of having access to all of fbdev's internal structures.

The 2.6 code is already a big step compared to 2.4, and most of the bugs
plaguing fbcon/fbcore has been ironed out.  I don't want a new interface
again until after things settle down a bit more and drivers get updated to
the new core.

Anyway, you can code the part where a new modelist is to be created.  Then
send an event that the entire modelist is to be changed, passing the fb_info
structure and the new modelist.  fbcon captures the event (and I'll code
this part where fbcon starts using the new modelist and resizes each
console).  After which, the old modelist can be destroyed. 

Sample code:

struct fb_event event;

/* create new_modelist */
event.info = info;
event.data = new_modelist;
notifier_call_chain(&fb_notifier_list, FB_EVENT_NEW_MODELIST, &event);
/*destroy old_modelist */

Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  7:27       ` Jon Smirl
@ 2005-02-18  7:41         ` Antonino A. Daplas
  2005-02-18  7:42         ` Antonino A. Daplas
  1 sibling, 0 replies; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-18  7:41 UTC (permalink / raw)
  To: Jon Smirl, adaplas, James Simmons; +Cc: linux-fbdev-devel

On Friday 18 February 2005 15:27, Jon Smirl wrote:
> Next version of sysfs patch. Fills out more attributes. Feel free to
> add code for missing implementations. Modifies fbcon to copy mode
> structure instead of taking a reference to it. Modular fbdev is

Modifying fbcon to get a copy of the mode still won't work.  What if
the consoles are at 1600x1200, and then you plug in a new monitor
capable only of 1024x768 max?  So you still need to send an
event, and fbcon needs to capture this event so it can resize the
consoles to fit the new monitor.

Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  7:27       ` Jon Smirl
  2005-02-18  7:41         ` Antonino A. Daplas
@ 2005-02-18  7:42         ` Antonino A. Daplas
  2005-02-18 16:46           ` Jon Smirl
  1 sibling, 1 reply; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-18  7:42 UTC (permalink / raw)
  To: Jon Smirl, adaplas, James Simmons; +Cc: linux-fbdev-devel

On Friday 18 February 2005 15:27, Jon Smirl wrote:
> Next version of sysfs patch. Fills out more attributes. Feel free to
> add code for missing implementations. Modifies fbcon to copy mode
> structure instead of taking a reference to it. Modular fbdev is
> separate patch. Ultimately we should be able to eliminate the IOCTL
> code from fb_core and move it to a compatibility module.

Okay, I think I can start coding starting from this patch.

Thanks for the work Jon.

Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  7:31         ` Antonino A. Daplas
@ 2005-02-18  9:42           ` Geert Uytterhoeven
  0 siblings, 0 replies; 24+ messages in thread
From: Geert Uytterhoeven @ 2005-02-18  9:42 UTC (permalink / raw)
  To: Linux Frame Buffer Device Development; +Cc: Jon Smirl, adaplas, James Simmons

On Fri, 18 Feb 2005, Antonino A. Daplas wrote:
> On Friday 18 February 2005 10:59, Jon Smirl wrote:
> > fbcon really need to know the entire mode structure or could it work
> > with just the resolution?
> 
> fbcon only needs xres, yres, vxres and vyres.  But in order to preserve
> the graphics state per console, everything in var is required.

And visual/color depth (for modes `less' than 16 colors).

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  7:42         ` Antonino A. Daplas
@ 2005-02-18 16:46           ` Jon Smirl
  2005-02-18 21:59             ` Antonino A. Daplas
  0 siblings, 1 reply; 24+ messages in thread
From: Jon Smirl @ 2005-02-18 16:46 UTC (permalink / raw)
  To: adaplas; +Cc: linux-fbdev-devel, James Simmons

On Fri, 18 Feb 2005 15:42:50 +0800, Antonino A. Daplas
<adaplas@hotpop.com> wrote:
> On Friday 18 February 2005 15:27, Jon Smirl wrote:
> > Next version of sysfs patch. Fills out more attributes. Feel free to
> > add code for missing implementations. Modifies fbcon to copy mode
> > structure instead of taking a reference to it. Modular fbdev is
> > separate patch. Ultimately we should be able to eliminate the IOCTL
> > code from fb_core and move it to a compatibility module.
> 
> Okay, I think I can start coding starting from this patch.

Do you want to take over the sysfs support? If so, I will make some
changes to the radeonfb driver that I need. That will keep up from
conflicting.

-- 
Jon Smirl
jonsmirl@gmail.com


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18 16:46           ` Jon Smirl
@ 2005-02-18 21:59             ` Antonino A. Daplas
  2005-02-21 18:55               ` James Simmons
  2005-02-21 23:13               ` Antonino A. Daplas
  0 siblings, 2 replies; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-18 21:59 UTC (permalink / raw)
  To: Jon Smirl, adaplas; +Cc: linux-fbdev-devel, James Simmons

On Saturday 19 February 2005 00:46, Jon Smirl wrote:
> On Fri, 18 Feb 2005 15:42:50 +0800, Antonino A. Daplas
>
> <adaplas@hotpop.com> wrote:
> > On Friday 18 February 2005 15:27, Jon Smirl wrote:
> > > Next version of sysfs patch. Fills out more attributes. Feel free to
> > > add code for missing implementations. Modifies fbcon to copy mode
> > > structure instead of taking a reference to it. Modular fbdev is
> > > separate patch. Ultimately we should be able to eliminate the IOCTL
> > > code from fb_core and move it to a compatibility module.
> >
> > Okay, I think I can start coding starting from this patch.
>
> Do you want to take over the sysfs support? If so, I will make some
> changes to the radeonfb driver that I need. That will keep up from
> conflicting.

Actually, I plan to do the fbcon part only, capturing the event. I'll use
yours as the test bed, but you and James will have to agree on the best way
to add sysfs support to the fb core.

Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18  0:39       ` Jon Smirl
@ 2005-02-21 18:37         ` James Simmons
  2005-02-21 19:11           ` Jon Smirl
  0 siblings, 1 reply; 24+ messages in thread
From: James Simmons @ 2005-02-21 18:37 UTC (permalink / raw)
  To: Jon Smirl; +Cc: adaplas, linux-fbdev-devel, James Simmons


Here is a question. What about if the drivers are built and fbdev is 
modular? I will have to try it to see the results.

On Thu, 17 Feb 2005, Jon Smirl wrote:

> On Fri, 18 Feb 2005 08:04:46 +0800, Antonino A. Daplas
> <adaplas@hotpop.com> wrote:
> > If possible, separate the sysfs patch from making fbcore as module.
> 
> Split for making fbcore into a module. It's pretty minor.
> 
> -- 
> Jon Smirl
> jonsmirl@gmail.com
> 
> 
> diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig
> --- a/drivers/video/Kconfig	2005-02-17 19:11:37 -05:00
> +++ b/drivers/video/Kconfig	2005-02-17 19:11:37 -05:00
> @@ -5,7 +5,7 @@
>  menu "Graphics support"
>  
>  config FB
> -	bool "Support for frame buffer devices"
> +	tristate "Support for frame buffer devices"
>  	---help---
>  	  The frame buffer device provides an abstraction for the graphics
>  	  hardware. It represents the frame buffer of some video hardware and
> diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
> --- a/drivers/video/Makefile	2005-02-17 19:11:37 -05:00
> +++ b/drivers/video/Makefile	2005-02-17 19:11:37 -05:00
> @@ -8,11 +8,13 @@
>  obj-$(CONFIG_LOGO)		  += logo/
>  obj-$(CONFIG_SYSFS)		  += backlight/
>  
> -obj-$(CONFIG_FB)                  += fbmem.o fbmon.o fbcmap.o
> fbsysfs.o modedb.o softcursor.o
> +obj-$(CONFIG_FB)                  += fb.o
> +fb-y                              := fbmem.o fbmon.o fbcmap.o
> fbsysfs.o modedb.o softcursor.o
>  # Only include macmodes.o if we have FB support and are PPC
> -ifeq ($(CONFIG_FB),y)
> -obj-$(CONFIG_PPC)                 += macmodes.o
> +ifneq ($(CONFIG_FB),n)
> +fb-$(CONFIG_PPC)                  += macmodes.o
>  endif
> +fb-objs                           := $(fb-y)
>  
>  # Hardware specific drivers go first
>  obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
> diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
> --- a/drivers/video/fbmem.c	2005-02-17 19:11:37 -05:00
> +++ b/drivers/video/fbmem.c	2005-02-17 19:11:37 -05:00
> @@ -1204,7 +1204,22 @@
>  	}
>  	return 0;
>  }
> +
> +void __exit
> +fbmem_exit(void)
> +{
> +	class_simple_destroy(fb_class);
> +}
> +
> +#ifdef MODULE
> +module_init(fbmem_init);
> +module_exit(fbmem_exit);
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Framebuffer base");
> +#else
>  subsys_initcall(fbmem_init);
> +subsys_exitcall(fbmem_exit);
> +#endif
>  
>  static char *video_options[FB_MAX];
>  static int ofonly;
> 


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18 21:59             ` Antonino A. Daplas
@ 2005-02-21 18:55               ` James Simmons
  2005-02-21 19:13                 ` Jon Smirl
  2005-02-21 23:13               ` Antonino A. Daplas
  1 sibling, 1 reply; 24+ messages in thread
From: James Simmons @ 2005-02-21 18:55 UTC (permalink / raw)
  To: linux-fbdev-devel; +Cc: Jon Smirl, adaplas, James Simmons


> > Do you want to take over the sysfs support? If so, I will make some
> > changes to the radeonfb driver that I need. That will keep up from
> > conflicting.
> 
> Actually, I plan to do the fbcon part only, capturing the event. I'll use
> yours as the test bed, but you and James will have to agree on the best way
> to add sysfs support to the fb core.

We are attempting to work that out. Right now also I'm working on resource 
management for fbdev. I have a patch coming but it needs work. I consider 
it more important that sysfs right now. I will be sending the first run at 
that resource management today.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-21 18:37         ` James Simmons
@ 2005-02-21 19:11           ` Jon Smirl
  2005-02-21 21:16             ` James Simmons
  0 siblings, 1 reply; 24+ messages in thread
From: Jon Smirl @ 2005-02-21 19:11 UTC (permalink / raw)
  To: James Simmons; +Cc: adaplas, linux-fbdev-devel, James Simmons

On Mon, 21 Feb 2005 18:37:45 +0000 (GMT), James Simmons
<jsimmons@www.infradead.org> wrote:
> 
> Here is a question. What about if the drivers are built and fbdev is
> modular? I will have to try it to see the results.

If a driver is built in you can't use fb as a module. Kernel kconfig
controls this automatically for you. If you pick fb as a module you
will only get modules as a choice on the drivers. If you pick built in
you can build the drivers either way. You can't compile fb as a module
and have built in drivers, the kernel will refuse to build.

-- 
Jon Smirl
jonsmirl@gmail.com


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-21 18:55               ` James Simmons
@ 2005-02-21 19:13                 ` Jon Smirl
  0 siblings, 0 replies; 24+ messages in thread
From: Jon Smirl @ 2005-02-21 19:13 UTC (permalink / raw)
  To: James Simmons; +Cc: linux-fbdev-devel, adaplas, James Simmons

On Mon, 21 Feb 2005 18:55:23 +0000 (GMT), James Simmons
<jsimmons@www.infradead.org> wrote:
> We are attempting to work that out. Right now also I'm working on resource
> management for fbdev. I have a patch coming but it needs work. I consider
> it more important that sysfs right now. I will be sending the first run at
> that resource management today.

The work on framebuffer is being driven by our goal of demoing
XGL/mesa-solo/DRM&fbdev at OLS this summer. The sysfs code is a key
part of being able to set modes without being root.

-- 
Jon Smirl
jonsmirl@gmail.com


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-21 19:11           ` Jon Smirl
@ 2005-02-21 21:16             ` James Simmons
  0 siblings, 0 replies; 24+ messages in thread
From: James Simmons @ 2005-02-21 21:16 UTC (permalink / raw)
  To: Jon Smirl; +Cc: adaplas, linux-fbdev-devel, James Simmons


> <jsimmons@www.infradead.org> wrote:
> > 
> > Here is a question. What about if the drivers are built and fbdev is
> > modular? I will have to try it to see the results.
> 
> If a driver is built in you can't use fb as a module. Kernel kconfig
> controls this automatically for you. If you pick fb as a module you
> will only get modules as a choice on the drivers. If you pick built in
> you can build the drivers either way. You can't compile fb as a module
> and have built in drivers, the kernel will refuse to build.

So kbuild is smart enough to handle this. In the old days you could break 
the build.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-18 21:59             ` Antonino A. Daplas
  2005-02-21 18:55               ` James Simmons
@ 2005-02-21 23:13               ` Antonino A. Daplas
  2005-02-21 23:15                 ` Antonino A. Daplas
  1 sibling, 1 reply; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-21 23:13 UTC (permalink / raw)
  To: Jon Smirl, adaplas; +Cc: linux-fbdev-devel, James Simmons

[-- Attachment #1: Type: text/plain, Size: 1577 bytes --]

On Saturday 19 February 2005 05:59, Antonino A. Daplas wrote:
> On Saturday 19 February 2005 00:46, Jon Smirl wrote:
> > On Fri, 18 Feb 2005 15:42:50 +0800, Antonino A. Daplas
> >
> > <adaplas@hotpop.com> wrote:
> > > On Friday 18 February 2005 15:27, Jon Smirl wrote:
> > > > Next version of sysfs patch. Fills out more attributes. Feel free to
> > > > add code for missing implementations. Modifies fbcon to copy mode
> > > > structure instead of taking a reference to it. Modular fbdev is
> > > > separate patch. Ultimately we should be able to eliminate the IOCTL
> > > > code from fb_core and move it to a compatibility module.
> > >
> > > Okay, I think I can start coding starting from this patch.
> >
> > Do you want to take over the sysfs support? If so, I will make some
> > changes to the radeonfb driver that I need. That will keep up from
> > conflicting.
>
> Actually, I plan to do the fbcon part only, capturing the event. I'll use
> yours as the test bed, but you and James will have to agree on the best way
> to add sysfs support to the fb core.

Attached are 2 test patches.  The first (fbsysfs.diff) is Jon's practically
unmodified code, but with cosmetic changes and the mode copy reverted back
to mode pointer (I prefer the pointer since it will crash rather than
silently fail if there's a bug, besides consuming less memory).

The second patch (fbcon-new-modelist.diff) adds a new event,
FB_EVENT_NEW_MODELIST.  This is sent by store_modes() via fb_new_modelist().
The event is captured by fbcon and resizes all consoles based on the new
modelist.

Tony

[-- Attachment #2: fbsysfs.diff --]
[-- Type: text/x-diff, Size: 11216 bytes --]

diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-15 21:25:14 +08:00
+++ b/drivers/video/fbmem.c	2005-02-18 15:17:45 +08:00
@@ -1059,7 +1059,6 @@
 register_framebuffer(struct fb_info *fb_info)
 {
 	int i;
-	struct class_device *c;
 	struct fb_event event;
 
 	if (num_registered_fb == FB_MAX)
@@ -1070,13 +1069,15 @@
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
+	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
@@ -1135,6 +1136,7 @@
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
+	fb_cleanup_class_device(fb_info);
 	class_simple_device_remove(MKDEV(FB_MAJOR, i));
 	return 0;
 }
diff -Nru a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c	2004-10-19 20:21:42 +08:00
+++ b/drivers/video/fbsysfs.c	2005-02-20 07:56:25 +08:00
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
+#include <linux/console.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -57,6 +58,7 @@
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -71,6 +73,307 @@
 {
 	kfree(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+	int err;
+
+	var->activate |= FB_ACTIVATE_FORCE;
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_set_var(fb_info, var);
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err)
+		return err;
+	return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset,
+		       const struct fb_videomode *mode)
+{
+	char m = 'U';
+	if (mode->flag & FB_MODE_IS_DETAILED)
+		m = 'D';
+	if (mode->flag & FB_MODE_IS_VESA)
+		m = 'V';
+	if (mode->flag & FB_MODE_IS_STANDARD)
+		m = 'S';
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const char * buf,
+			  size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, 0, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			var = fb_info->var;
+			fb_videomode_to_var(&var, mode);
+			if ((err = activate(fb_info, &var)))
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const char * buf,
+			   size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	int i = count / sizeof(struct fb_videomode);
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	fb_destroy_modelist(&fb_info->modelist);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i,
+				 &fb_info->modelist);
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	unsigned int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(buf, i, mode);
+	}
+	return i;
+}
+
+static ssize_t store_bpp(struct class_device *class_device, const char * buf,
+			 size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char ** last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.bits_per_pixel = simple_strtoul(buf, last, 0);
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_bpp(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_virtual(struct class_device *class_device,
+			     const char * buf, size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xres_virtual = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yres_virtual = simple_strtoul(last, &last, 0);
+	printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual,
+	       var.yres_virtual);
+
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_virtual(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual,
+			fb_info->var.xres_virtual);
+}
+
+static ssize_t store_cmap(struct class_device *class_device, const char * buf,
+			  size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cmap(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	unsigned int offset = 0, i;
+
+	if (!fb_info->cmap.red || !fb_info->cmap.blue ||
+	    fb_info->cmap.green || fb_info->cmap.transp)
+		return -EINVAL;
+
+	for (i = 0; i < fb_info->cmap.len; i++) {
+		offset += snprintf(buf, PAGE_SIZE - offset,
+				   "%d,%d,%d,%d,%d\n", i + fb_info->cmap.start,
+				   fb_info->cmap.red[i], fb_info->cmap.blue[i],
+				   fb_info->cmap.green[i],
+				   fb_info->cmap.transp[i]);
+	}
+	return offset;
+}
+
+static ssize_t store_blank(struct class_device *class_device, const char * buf,
+			   size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	char *last = NULL;
+	int err;
+
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_blank(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_console(struct class_device *class_device,
+			     const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_console(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_cursor(struct class_device *class_device,
+			    const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cursor(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_pan(struct class_device *class_device, const char * buf,
+			 size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xoffset = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yoffset = simple_strtoul(last, &last, 0);
+
+	acquire_console_sem();
+	err = fb_pan_display(fb_info, &var);
+	release_console_sem();
+
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_pan(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
+			fb_info->var.xoffset);
+}
+
+struct class_device_attribute class_device_attrs[] = {
+	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
+	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
+	__ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
+	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
+	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
+	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
+	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
+};
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+	class_set_devdata(fb_info->class_device, fb_info);
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_create_file(fb_info->class_device,
+					 &class_device_attrs[i]);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_remove_file(fb_info->class_device,
+					 &class_device_attrs[i]);
+}
+
+
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	2005-02-16 19:55:25 +08:00
+++ b/include/linux/fb.h	2005-02-18 15:17:45 +08:00
@@ -715,8 +715,10 @@
 	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
+	struct fb_videomode *mode;	/* current mode */
 	struct fb_ops *fbops;
 	struct device *device;
+	struct class_device *class_device; /* sysfs per device attrs */
 #ifdef CONFIG_FB_TILEBLITTING
 	struct fb_tile_ops *tileops;    /* Tile Blitting */
 #endif
@@ -833,6 +835,8 @@
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int fb_init_class_device(struct fb_info *fb_info);
+extern void fb_cleanup_class_device(struct fb_info *head);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0

[-- Attachment #3: fbcon-new-modelist.diff --]
[-- Type: text/x-diff, Size: 442 bytes --]

 drivers/video/console/bitblit.c |    2 -
 drivers/video/console/fbcon.c   |   68 +++++++++++++++++++++++++++++-----------
 drivers/video/fbmem.c           |   43 ++++++++++++++++++++++---
 drivers/video/fbsysfs.c         |   12 ++++++-
 drivers/video/modedb.c          |   42 ++++++++++++++++++++++++
 drivers/video/nvidia/nvidia.c   |    2 -
 include/linux/fb.h              |    7 +++-
 7 files changed, 149 insertions(+), 27 deletions(-)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-21 23:13               ` Antonino A. Daplas
@ 2005-02-21 23:15                 ` Antonino A. Daplas
  2005-02-25  0:04                   ` Jon Smirl
  0 siblings, 1 reply; 24+ messages in thread
From: Antonino A. Daplas @ 2005-02-21 23:15 UTC (permalink / raw)
  To: adaplas, Jon Smirl; +Cc: linux-fbdev-devel, James Simmons

On Tuesday 22 February 2005 07:13, Antonino A. Daplas wrote:
> On Saturday 19 February 2005 05:59, Antonino A. Daplas wrote:
> > On Saturday 19 February 2005 00:46, Jon Smirl wrote:
> > > On Fri, 18 Feb 2005 15:42:50 +0800, Antonino A. Daplas
> > >
> > > <adaplas@hotpop.com> wrote:
> > > > On Friday 18 February 2005 15:27, Jon Smirl wrote:
> > > > > Next version of sysfs patch. Fills out more attributes. Feel free
> > > > > to add code for missing implementations. Modifies fbcon to copy
> > > > > mode structure instead of taking a reference to it. Modular fbdev
> > > > > is separate patch. Ultimately we should be able to eliminate the
> > > > > IOCTL code from fb_core and move it to a compatibility module.
> > > >
> > > > Okay, I think I can start coding starting from this patch.
> > >
> > > Do you want to take over the sysfs support? If so, I will make some
> > > changes to the radeonfb driver that I need. That will keep up from
> > > conflicting.
> >
> > Actually, I plan to do the fbcon part only, capturing the event. I'll use
> > yours as the test bed, but you and James will have to agree on the best
> > way to add sysfs support to the fb core.
>
> Attached are 2 test patches.  The first (fbsysfs.diff) is Jon's practically
> unmodified code, but with cosmetic changes and the mode copy reverted back
> to mode pointer (I prefer the pointer since it will crash rather than
> silently fail if there's a bug, besides consuming less memory).
>
> The second patch (fbcon-new-modelist.diff) adds a new event,
> FB_EVENT_NEW_MODELIST.  This is sent by store_modes() via
> fb_new_modelist(). The event is captured by fbcon and resizes all consoles
> based on the new modelist.
>

Grr, fbcon-new-modelist.diff contains the diffstat only.  Here's the new patch.

Tony

diff -Nru a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
--- a/drivers/video/console/bitblit.c	2004-11-17 18:32:21 +08:00
+++ b/drivers/video/console/bitblit.c	2005-02-21 20:43:09 +08:00
@@ -39,7 +39,7 @@
 {
 	int attribute = 0;
 
-	if (fb_get_color_depth(info) == 1) {
+	if (fb_get_color_depth(&info->var) == 1) {
 		if (attr_underline(c))
 			attribute |= FBCON_ATTRIBUTE_UNDERLINE;
 		if (attr_reverse(c))
diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	2005-02-19 20:15:41 +08:00
+++ b/drivers/video/console/fbcon.c	2005-02-21 20:43:09 +08:00
@@ -182,8 +182,10 @@
 static __inline__ void ypan_down(struct vc_data *vc, int count);
 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
 			    int dy, int dx, int height, int width, u_int y_break);
-static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc);
-static void fbcon_preset_disp(struct fb_info *info, int unit);
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			   struct vc_data *vc);
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			      int unit);
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
 			      int line, int count, int dy);
 
@@ -209,7 +211,7 @@
 static inline int get_color(struct vc_data *vc, struct fb_info *info,
 	      u16 c, int is_fg)
 {
-	int depth = fb_get_color_depth(info);
+	int depth = fb_get_color_depth(&info->var);
 	int color = 0;
 
 	if (console_blanked) {
@@ -418,7 +420,7 @@
 	 * remove underline attribute from erase character
 	 * if black and white framebuffer.
 	 */
-	if (fb_get_color_depth(info) == 1)
+	if (fb_get_color_depth(&info->var) == 1)
 		erase &= ~0x400;
 	logo_height = fb_prepare_logo(info);
 	logo_lines = (logo_height + vc->vc_font.height - 1) /
@@ -595,9 +597,9 @@
 		info->fbops->fb_set_par(info);
 
 	if (vc)
-		fbcon_set_disp(info, vc);
+		fbcon_set_disp(info, &info->var, vc);
 	else
-		fbcon_preset_disp(info, unit);
+		fbcon_preset_disp(info, &info->var, unit);
 
 	if (show_logo) {
 		struct vc_data *fg_vc = vc_cons[fg_console].d;
@@ -917,7 +919,7 @@
 	}
 	if (p->userfont)
 		charcnt = FNTCHARCNT(p->fontdata);
-	vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+	vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	if (charcnt == 256) {
 		vc->vc_hi_font_mask = 0;
@@ -1123,13 +1125,14 @@
 /*
  * If no vc is existent yet, just set struct display
  */
-static void fbcon_preset_disp(struct fb_info *info, int unit)
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			      int unit)
 {
 	struct display *p = &fb_display[unit];
 	struct display *t = &fb_display[fg_console];
 
-	info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-	if (var_to_display(p, &info->var, info))
+	var->xoffset = var->yoffset = p->yscroll = 0;
+	if (var_to_display(p, var, info))
 		return;
 
 	p->fontdata = t->fontdata;
@@ -1138,15 +1141,16 @@
 		REFCOUNT(p->fontdata)++;
 }
 
-static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			   struct vc_data *vc)
 {
 	struct display *p = &fb_display[vc->vc_num], *t;
 	struct vc_data **default_mode = vc->vc_display_fg;
 	struct vc_data *svc = *default_mode;
 	int rows, cols, charcnt = 256;
 
-	info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-	if (var_to_display(p, &info->var, info))
+	var->xoffset = var->yoffset = p->yscroll = 0;
+	if (var_to_display(p, var, info))
 		return;
 	t = &fb_display[svc->vc_num];
 	if (!vc->vc_font.data) {
@@ -1160,7 +1164,7 @@
 	if (p->userfont)
 		charcnt = FNTCHARCNT(p->fontdata);
 
-	vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+	vc->vc_can_do_color = (fb_get_color_depth(var) != 1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	if (charcnt == 256) {
 		vc->vc_hi_font_mask = 0;
@@ -1175,8 +1179,8 @@
 	if (!*vc->vc_uni_pagedir_loc)
 		con_copy_unimap(vc, svc);
 
-	cols = info->var.xres / vc->vc_font.width;
-	rows = info->var.yres / vc->vc_font.height;
+	cols = var->xres / vc->vc_font.width;
+	rows = var->yres / vc->vc_font.height;
 	vc_resize(vc, cols, rows);
 	if (CON_IS_VISIBLE(vc)) {
 		update_screen(vc);
@@ -1955,7 +1959,7 @@
 	set_blitting_type(vc, info, p);
 	((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
 
-	vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+	vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	updatescrollmode(p, info, vc);
 
@@ -2326,7 +2330,7 @@
 	if (fbcon_is_inactive(vc, info))
 		return -EINVAL;
 
-	depth = fb_get_color_depth(info);
+	depth = fb_get_color_depth(&info->var);
 	if (depth > 3) {
 		for (i = j = 0; i < 16; i++) {
 			k = table[i];
@@ -2658,6 +2662,31 @@
 	ops->blank_state = blank;
 }
 
+static void fbcon_new_modelist(struct fb_info *info)
+{
+	int i;
+	struct vc_data *vc;
+	struct fb_var_screeninfo var;
+	struct fb_videomode *mode;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (registered_fb[con2fb_map[i]] != info)
+			continue;
+		if (!fb_display[i].mode)
+			continue;
+		vc = vc_cons[i].d;
+		display_to_var(&var, &fb_display[i]);
+		mode = fb_find_nearest_mode(&var, &info->modelist);
+		fb_videomode_to_var(&var, mode);
+
+		if (vc)
+			fbcon_set_disp(info, &var, vc);
+		else
+			fbcon_preset_disp(info, &var, i);
+
+	}
+}
+
 static int fbcon_event_notify(struct notifier_block *self, 
 			      unsigned long action, void *data)
 {
@@ -2695,6 +2724,9 @@
 		break;
 	case FB_EVENT_BLANK:
 		fbcon_fb_blanked(info, *(int *)event->data);
+		break;
+	case FB_EVENT_NEW_MODELIST:
+		fbcon_new_modelist(info);
 		break;
 	}
 
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-18 15:17:45 +08:00
+++ b/drivers/video/fbmem.c	2005-02-21 20:43:10 +08:00
@@ -62,10 +62,8 @@
  * Helpers
  */
 
-int fb_get_color_depth(struct fb_info *info)
+int fb_get_color_depth(struct fb_var_screeninfo *var)
 {
-	struct fb_var_screeninfo *var = &info->var;
-
 	if (var->green.length == var->blue.length &&
 	    var->green.length == var->red.length &&
 	    !var->green.offset && !var->blue.offset &&
@@ -300,7 +298,7 @@
 	const u8 *src = logo->data;
 	u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
 
-	if (fb_get_color_depth(info) == 3)
+	if (fb_get_color_depth(&info->var) == 3)
 		fg = 7;
 
 	switch (depth) {
@@ -365,7 +363,7 @@
 
 int fb_prepare_logo(struct fb_info *info)
 {
-	int depth = fb_get_color_depth(info);
+	int depth = fb_get_color_depth(&info->var);
 
 	memset(&fb_logo, 0, sizeof(struct logo_data));
 
@@ -1209,6 +1207,40 @@
 }
 subsys_initcall(fbmem_init);
 
+int fb_new_modelist(struct fb_info *info)
+{
+	struct fb_event event;
+	struct fb_var_screeninfo var = info->var;
+	struct list_head *pos, *n;
+	struct fb_modelist *modelist;
+	struct fb_videomode *m, mode;
+	int err = 1;
+
+	list_for_each_safe(pos, n, &info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		m = &modelist->mode;
+		fb_videomode_to_var(&var, m);
+		var.activate = FB_ACTIVATE_TEST;
+		err = fb_set_var(info, &var);
+		fb_var_to_videomode(&mode, &var);
+		if (err || !fb_mode_is_equal(m, &mode)) {
+			list_del(pos);
+			kfree(pos);
+		}
+	}
+
+	err = 1;
+
+	if (!list_empty(&info->modelist)) {
+		event.info = info;
+		err = notifier_call_chain(&fb_notifier_list,
+					   FB_EVENT_NEW_MODELIST,
+					   &event);
+	}
+
+	return err;
+}
+
 static char *video_options[FB_MAX];
 static int ofonly;
 
@@ -1320,5 +1352,6 @@
 EXPORT_SYMBOL(fb_register_client);
 EXPORT_SYMBOL(fb_unregister_client);
 EXPORT_SYMBOL(fb_get_options);
+EXPORT_SYMBOL(fb_new_modelist);
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c	2005-02-20 07:56:25 +08:00
+++ b/drivers/video/fbsysfs.c	2005-02-21 20:43:10 +08:00
@@ -151,13 +151,23 @@
 {
 	struct fb_info *fb_info =
 		(struct fb_info *)class_get_devdata(class_device);
+	LIST_HEAD(old_list);
 	int i = count / sizeof(struct fb_videomode);
+	
 	if (i * sizeof(struct fb_videomode) != count)
 		return -EINVAL;
 
-	fb_destroy_modelist(&fb_info->modelist);
+	acquire_console_sem();
+	list_splice(&fb_info->modelist, &old_list);
 	fb_videomode_to_modelist((struct fb_videomode *)buf, i,
 				 &fb_info->modelist);
+	if (fb_new_modelist(fb_info)) {
+		fb_destroy_modelist(&fb_info->modelist);
+		list_splice(&old_list, &fb_info->modelist);
+	} else 
+		fb_destroy_modelist(&old_list);
+
+	release_console_sem();
 
 	return 0;
 }
diff -Nru a/drivers/video/modedb.c b/drivers/video/modedb.c
--- a/drivers/video/modedb.c	2005-02-15 22:54:57 +08:00
+++ b/drivers/video/modedb.c	2005-02-21 20:43:10 +08:00
@@ -726,6 +726,47 @@
 }
 
 /**
+ * fb_find_nearest_mode - find mode closest video mode
+ *
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to modelist
+ *
+ * Finds best matching videomode, smaller or greater in dimension.
+ * If more than 1 videomode is found, will return the videomode with
+ * the closest refresh rate
+ */
+struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var,
+					  struct list_head *head)
+{
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode, *best = NULL;
+	u32 diff = -1, diff_refresh = -1;
+
+	list_for_each(pos, head) {
+		u32 d;
+
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+
+		d = abs(mode->xres - var->xres) + 
+			abs(mode->yres - var->yres);
+		if (diff > d) {
+			diff = d;
+			best = mode;
+		} else if (diff == d) {
+			d = abs(mode->refresh - best->refresh);
+			if (diff_refresh > d) {
+				diff_refresh = d;
+				best = mode;
+			}
+		}
+	}
+	
+	return best;
+}    
+
+/**
  * fb_match_mode - find a videomode which exactly matches the timings in var
  * @var: pointer to struct fb_var_screeninfo
  * @head: pointer to struct list_head of modelist
@@ -850,5 +891,6 @@
 EXPORT_SYMBOL(fb_destroy_modelist);
 EXPORT_SYMBOL(fb_match_mode);
 EXPORT_SYMBOL(fb_find_best_mode);
+EXPORT_SYMBOL(fb_find_nearest_mode);
 EXPORT_SYMBOL(fb_videomode_to_modelist);
 EXPORT_SYMBOL(fb_find_mode);
diff -Nru a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
--- a/drivers/video/nvidia/nvidia.c	2005-02-16 21:44:53 +08:00
+++ b/drivers/video/nvidia/nvidia.c	2005-02-21 20:43:10 +08:00
@@ -657,7 +657,7 @@
 {
 	struct nvidia_par *par = info->par;
 	struct _riva_hw_state *state = &par->ModeReg;
-	int i, depth = fb_get_color_depth(info);
+	int i, depth = fb_get_color_depth(&info->var);
 	int h_display = info->var.xres / 8 - 1;
 	int h_start = (info->var.xres + info->var.right_margin) / 8 - 1;
 	int h_end = (info->var.xres + info->var.right_margin +
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	2005-02-18 15:17:45 +08:00
+++ b/include/linux/fb.h	2005-02-21 20:43:10 +08:00
@@ -493,6 +493,8 @@
 #define FB_EVENT_SET_CONSOLE_MAP        0x07
 /*      A display blank is requested       */
 #define FB_EVENT_BLANK                  0x08
+/*      Private modelist is to be replaced */
+#define FB_EVENT_NEW_MODELIST           0x09
 
 struct fb_event {
 	struct fb_info *info;
@@ -825,8 +827,9 @@
 				u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
 				u32 height);
 extern void fb_set_suspend(struct fb_info *info, int state);
-extern int fb_get_color_depth(struct fb_info *info);
+extern int fb_get_color_depth(struct fb_var_screeninfo *var);
 extern int fb_get_options(char *name, char **option);
+extern int fb_new_modelist(struct fb_info *info);
 extern int fb_blank(struct fb_info *info, int blank);
 
 extern struct fb_info *registered_fb[FB_MAX];
@@ -882,6 +885,8 @@
 					  struct list_head *head);
 extern struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
 					      struct list_head *head);
+extern struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var,
+						 struct list_head *head);
 extern void fb_destroy_modelist(struct list_head *head);
 extern void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
 				     struct list_head *head);

> Tony




-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Patch to add mode setting to sysfs
  2005-02-21 23:15                 ` Antonino A. Daplas
@ 2005-02-25  0:04                   ` Jon Smirl
  0 siblings, 0 replies; 24+ messages in thread
From: Jon Smirl @ 2005-02-25  0:04 UTC (permalink / raw)
  To: adaplas; +Cc: linux-fbdev-devel, James Simmons

[-- Attachment #1: Type: text/plain, Size: 810 bytes --]

On Tue, 22 Feb 2005 07:15:13 +0800, Antonino A. Daplas
<adaplas@hotpop.com> wrote:
> > Attached are 2 test patches.  The first (fbsysfs.diff) is Jon's practically
> > unmodified code, but with cosmetic changes and the mode copy reverted back
> > to mode pointer (I prefer the pointer since it will crash rather than
> > silently fail if there's a bug, besides consuming less memory).
> >
> > The second patch (fbcon-new-modelist.diff) adds a new event,
> > FB_EVENT_NEW_MODELIST.  This is sent by store_modes() via
> > fb_new_modelist(). The event is captured by fbcon and resizes all consoles
> > based on the new modelist.

What are you diffing this against? I don't have an nvidia fbdev driver
in my Linus bk tree.

Can you regenerate against Linus bk plus my sysfs.patch?

-- 
Jon Smirl
jonsmirl@gmail.com

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sysfs.patch --]
[-- Type: text/x-diff; name="sysfs.patch", Size: 13267 bytes --]

diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/console/fbcon.c	2005-02-18 02:17:45 -05:00
@@ -681,6 +681,8 @@
 			  struct fb_var_screeninfo *var,
 			  struct fb_info *info)
 {
+	struct fb_videomode *mode;
+
 	disp->xres_virtual = var->xres_virtual;
 	disp->yres_virtual = var->yres_virtual;
 	disp->bits_per_pixel = var->bits_per_pixel;
@@ -693,17 +695,18 @@
 	disp->green = var->green;
 	disp->blue = var->blue;
 	disp->transp = var->transp;
-	disp->mode = fb_match_mode(var, &info->modelist);
-	if (disp->mode == NULL)
+	mode = fb_match_mode(var, &info->modelist);
+	if (mode == NULL)
 		/* This should not happen */
 		return -EINVAL;
+	disp->mode = *mode;
 	return 0;
 }
 
 static void display_to_var(struct fb_var_screeninfo *var,
 			   struct display *disp)
 {
-	fb_videomode_to_var(var, disp->mode);
+	fb_videomode_to_var(var, &disp->mode);
 	var->xres_virtual = disp->xres_virtual;
 	var->yres_virtual = disp->yres_virtual;
 	var->bits_per_pixel = disp->bits_per_pixel;
@@ -2605,9 +2608,9 @@
 		if (fb_info != info)
 			continue;
 		p = &fb_display[i];
-		if (!p || !p->mode)
+		if (!p)
 			continue;
-		if (fb_mode_is_equal(p->mode, mode)) {
+		if (fb_mode_is_equal(&p->mode, mode)) {
 			found = 1;
 			break;
 		}
diff -Nru a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
--- a/drivers/video/console/fbcon.h	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/console/fbcon.h	2005-02-18 02:17:45 -05:00
@@ -45,7 +45,7 @@
     struct fb_bitfield green;
     struct fb_bitfield blue;
     struct fb_bitfield transp;
-    struct fb_videomode *mode;
+    struct fb_videomode mode;
 };
 
 struct fbcon_ops {
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/fbmem.c	2005-02-18 02:17:45 -05:00
@@ -1058,7 +1058,6 @@
 register_framebuffer(struct fb_info *fb_info)
 {
 	int i;
-	struct class_device *c;
 	struct fb_event event;
 
 	if (num_registered_fb == FB_MAX)
@@ -1069,13 +1068,15 @@
 			break;
 	fb_info->node = i;
 
-	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
 				    fb_info->device, "fb%d", i);
-	if (IS_ERR(c)) {
+	if (IS_ERR(fb_info->class_device)) {
 		/* Not fatal */
-		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(c));
-	}
-	
+		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
 	if (fb_info->pixmap.addr == NULL) {
 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
 		if (fb_info->pixmap.addr) {
@@ -1134,6 +1135,7 @@
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
+	fb_cleanup_class_device(fb_info);
 	class_simple_device_remove(MKDEV(FB_MAJOR, i));
 	return 0;
 }
diff -Nru a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
--- a/drivers/video/fbsysfs.c	2005-02-18 02:17:45 -05:00
+++ b/drivers/video/fbsysfs.c	2005-02-18 02:17:45 -05:00
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/fb.h>
+#include <linux/console.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -57,6 +58,7 @@
 #undef PADDING
 #undef BYTES_PER_LONG
 }
+EXPORT_SYMBOL(framebuffer_alloc);
 
 /**
  * framebuffer_release - marks the structure available for freeing
@@ -71,6 +73,276 @@
 {
 	kfree(info);
 }
-
 EXPORT_SYMBOL(framebuffer_release);
-EXPORT_SYMBOL(framebuffer_alloc);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+	int err;
+	
+	var->activate |= FB_ACTIVATE_FORCE;
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_set_var(fb_info, var);
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err)
+		return err;
+	return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset, const struct fb_videomode *mode)
+{
+	char m = 'U';
+	if (mode->flag & FB_MODE_IS_DETAILED)
+		m = 'D';
+	if (mode->flag & FB_MODE_IS_VESA)
+		m = 'V';
+	if (mode->flag & FB_MODE_IS_STANDARD)
+		m = 'S';
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, 0, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			var = fb_info->var;
+			fb_videomode_to_var(&var, mode);
+			if ((err = activate(fb_info, &var)))
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	int i = count / sizeof(struct fb_videomode);
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	fb_destroy_modelist(&fb_info->modelist);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i, &fb_info->modelist);
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	unsigned int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(buf, i, mode);
+	}
+	return i;
+}
+
+static ssize_t store_bpp(struct class_device *class_device, const char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char ** last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.bits_per_pixel = simple_strtoul(buf, last, 0);
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_bpp(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_virtual(struct class_device *class_device, const char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xres_virtual = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yres_virtual = simple_strtoul(last, &last, 0);
+	printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual, var.yres_virtual);
+	
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_virtual(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual, fb_info->var.xres_virtual);
+}
+
+static ssize_t store_cmap(struct class_device *class_device, const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cmap(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	unsigned int offset = 0, i;
+	
+	if (!fb_info->cmap.red || !fb_info->cmap.blue || fb_info->cmap.green || fb_info->cmap.transp)
+		return -EINVAL;
+	
+	for (i = 0; i < fb_info->cmap.len; i++) {
+		offset += snprintf(buf, PAGE_SIZE - offset, "%d,%d,%d,%d,%d\n", i + fb_info->cmap.start,
+				   fb_info->cmap.red[i], fb_info->cmap.blue[i], fb_info->cmap.green[i], 
+				   fb_info->cmap.transp[i]); 
+	}
+	return offset;
+}
+
+static ssize_t store_blank(struct class_device *class_device, const char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	char *last = NULL;
+	int err;
+
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_blank(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_console(struct class_device *class_device, const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_console(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_cursor(struct class_device *class_device, const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cursor(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_pan(struct class_device *class_device, const char * buf, size_t count)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xoffset = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yoffset = simple_strtoul(last, &last, 0);
+	
+	acquire_console_sem();
+	err = fb_pan_display(fb_info, &var);
+	release_console_sem();
+	
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_pan(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset, fb_info->var.xoffset);
+}
+
+struct class_device_attribute class_device_attrs[] = {
+	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
+	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
+	__ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
+	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
+	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
+	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
+	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
+};
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+	class_set_devdata(fb_info->class_device, fb_info);
+	
+	for (i = 0; i < sizeof(class_device_attrs)/sizeof(class_device_attrs[0]); i++)
+		class_device_create_file(fb_info->class_device, &class_device_attrs[i]);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(class_device_attrs)/sizeof(class_device_attrs[0]); i++)
+		class_device_remove_file(fb_info->class_device, &class_device_attrs[i]);
+}
+
+
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	2005-02-18 02:17:45 -05:00
+++ b/include/linux/fb.h	2005-02-18 02:17:45 -05:00
@@ -712,8 +712,10 @@
 	struct fb_pixmap sprite;	/* Cursor hardware mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
+	struct fb_videomode *mode;	/* current mode */
 	struct fb_ops *fbops;
 	struct device *device;
+	struct class_device *class_device; /* sysfs per device attrs */
 #ifdef CONFIG_FB_TILEBLITTING
 	struct fb_tile_ops *tileops;    /* Tile Blitting */
 #endif
@@ -830,6 +832,8 @@
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
+extern int fb_init_class_device(struct fb_info *fb_info);
+extern void fb_cleanup_class_device(struct fb_info *head);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2005-02-25  0:05 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-16 22:30 Patch to add mode setting to sysfs Jon Smirl
2005-02-16 22:47 ` James Simmons
2005-02-17  1:28   ` Jon Smirl
2005-02-17 13:50 ` Antonino A. Daplas
2005-02-17 20:49   ` Jon Smirl
2005-02-17 22:13     ` James Simmons
2005-02-18  0:04     ` Antonino A. Daplas
2005-02-18  0:39       ` Jon Smirl
2005-02-21 18:37         ` James Simmons
2005-02-21 19:11           ` Jon Smirl
2005-02-21 21:16             ` James Simmons
2005-02-18  2:59       ` Jon Smirl
2005-02-18  7:31         ` Antonino A. Daplas
2005-02-18  9:42           ` Geert Uytterhoeven
2005-02-18  7:27       ` Jon Smirl
2005-02-18  7:41         ` Antonino A. Daplas
2005-02-18  7:42         ` Antonino A. Daplas
2005-02-18 16:46           ` Jon Smirl
2005-02-18 21:59             ` Antonino A. Daplas
2005-02-21 18:55               ` James Simmons
2005-02-21 19:13                 ` Jon Smirl
2005-02-21 23:13               ` Antonino A. Daplas
2005-02-21 23:15                 ` Antonino A. Daplas
2005-02-25  0:04                   ` Jon Smirl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).