From 7a35dff56037cdc1fa0a46b11b48a0776928fc62 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 11 Feb 2004 07:29:54 -0800 Subject: [PATCH] New radeonfb Here is the new radeonfb. It doesn't remove the old one, just in case, though CONFIG_FB_RADEON now builds the new one. The new driver supports recent cards, has better monitor detection, including DDC2, fixes a couple of constants in the old driver, and a lot more. I had to add an empty fb_set_suspend() function to fbmem.c (the real implementation is in James tree and will be here soon). That means that Power Management on Apple laptops isn't completely right yet until the core fbdev fixes get in, but it's good enough for now. --- include/linux/fb.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/fb.h') diff --git a/include/linux/fb.h b/include/linux/fb.h index e6a2053fbd51..9a6fd61a00b8 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -526,6 +526,7 @@ extern void move_buf_unaligned(struct fb_info *info, u8 * dst, u8 * src, u32 idx); extern void move_buf_aligned(struct fb_info *info, u8 * dst, u8 * src, u32 d_pitch, u32 s_pitch, u32 height); +extern void fb_set_suspend(struct fb_info *info, int state); extern struct fb_info *registered_fb[FB_MAX]; extern int num_registered_fb; -- cgit v1.2.3 From 70fa9749e4b3a2b0debef832b1ddadf612177a97 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 12 Feb 2004 23:45:19 -0800 Subject: [PATCH] sh: Wrap fb_read/writeX() to __raw_read/writeX() From: Paul Mundt This adds sh to the list of platforms that wrap fb_readX/fb_writeX() to __raw_readX/__raw_writeX(). This is needed so that the generic fb read/write routines will wrap properly through the sh machvec and use the appropriate board-specific I/O routines. --- include/linux/fb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/fb.h') diff --git a/include/linux/fb.h b/include/linux/fb.h index 9a6fd61a00b8..e429edf7224d 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -476,7 +476,7 @@ struct fb_info { #define fb_writeq sbus_writeq #define fb_memset sbus_memset_io -#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) +#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) #define fb_readb __raw_readb #define fb_readw __raw_readw -- cgit v1.2.3 From cab892f99e5bede66787c137ac6b4a82716eee33 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Feb 2004 17:04:00 -0800 Subject: [PATCH] back out fbdev sysfs support This backs out James' sysfs support for fbdev again. It introduces a big, race for every driver not converted to framebuffer_{alloc,release} (that is every driver but Ben's new radeonfb). I've left in framebuffer_{alloc,release} as stubs so drivers can be converted to it gradually and once all drivers are done it can be enabled again. --- drivers/video/fbmem.c | 6 ------ drivers/video/fbsysfs.c | 50 +++++++------------------------------------------ include/linux/fb.h | 4 ---- 3 files changed, 7 insertions(+), 53 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 7b5d4e31c0cb..bff474679be9 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1228,9 +1228,6 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; - if (fb_add_class_device(fb_info)) - return -EINVAL; - if (fb_info->pixmap.addr == NULL) { fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); if (fb_info->pixmap.addr) { @@ -1279,7 +1276,6 @@ unregister_framebuffer(struct fb_info *fb_info) kfree(fb_info->pixmap.addr); registered_fb[i]=NULL; num_registered_fb--; - class_device_del(&fb_info->class_dev); return 0; } @@ -1307,8 +1303,6 @@ fbmem_init(void) if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); - class_register(&fb_class); - #ifdef CONFIG_FB_OF if (ofonly) { offb_init(); diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 13a51f3bcc1c..8b3bbe0c641b 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -9,50 +9,15 @@ * 2 of the License, or (at your option) any later version. */ -#include +/* + * Note: currently there's only stubs for framebuffer_alloc and + * framebuffer_release here. The reson for that is that until all drivers + * are converted to use it a sysfsification will open OOPSable races. + */ + #include #include -#define to_fb_info(class) container_of(class, struct fb_info, class_dev) - -static void release_fb_info(struct class_device *class_dev) -{ - struct fb_info *info = to_fb_info(class_dev); - - /* This doesn't harm */ - fb_dealloc_cmap(&info->cmap); - - kfree(info); -} - -struct class fb_class = { - .name = "graphics", - .release = &release_fb_info, -}; - -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - struct fb_info *info = to_fb_info(class_dev); - - return sprintf(buf, "%u:%u\n", FB_MAJOR, info->node); -} - -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - -int fb_add_class_device(struct fb_info *info) -{ - int retval; - - info->class_dev.class = &fb_class; - snprintf(info->class_dev.class_id, BUS_ID_SIZE, "fb%d", - info->node); - retval = class_device_register(&info->class_dev); - if (retval) - return retval; - return class_device_create_file(&info->class_dev, - &class_device_attr_dev); -} - /** * framebuffer_alloc - creates a new frame buffer info structure * @@ -82,7 +47,6 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) return NULL; memset(p, 0, fb_info_size + size); info = (struct fb_info *) p; - info->class_dev.dev = dev; if (size) info->par = p + fb_info_size; @@ -103,7 +67,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) */ void framebuffer_release(struct fb_info *info) { - class_device_put(&info->class_dev); + kfree(info); } EXPORT_SYMBOL(framebuffer_release); diff --git a/include/linux/fb.h b/include/linux/fb.h index e429edf7224d..b4a8f5c48312 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -448,7 +448,6 @@ struct fb_info { char *screen_base; /* Virtual address */ struct vc_data *display_fg; /* Console visible on this display */ int currcon; /* Current VC. */ - struct class_device class_dev; /* Sysfs data */ void *pseudo_palette; /* Fake palette of 16 colors */ /* From here on everything is device dependent */ void *par; @@ -533,9 +532,6 @@ extern int num_registered_fb; /* 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_add_class_device(struct fb_info *info); - -extern struct class fb_class; /* drivers/video/fbmon.c */ #define FB_MAXTIMINGS 0 -- cgit v1.2.3 From 7b377012f0937e0705c3f27367f10ec724e38966 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 14 Feb 2004 17:32:22 -0800 Subject: [PATCH] Fix fbdev pixmap locking This removes the broken locking code in the pixmaps, and rewrite the buffer access function to properly call fb_sync when needed. The old broken loocking is useless as we are covered by the console semaphore in all cases hopefully (except if I missed one :) --- drivers/video/console/fbcon.c | 6 ------ drivers/video/fbmem.c | 36 +++++++++++++++++++++--------------- drivers/video/softcursor.c | 2 -- include/linux/fb.h | 2 -- 4 files changed, 21 insertions(+), 25 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 50fe17ea95dd..c2d6237f7f09 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -354,8 +354,6 @@ static void putcs_unaligned(struct vc_data *vc, struct fb_info *info, info->fbops->fb_imageblit(info, image); image->dx += cnt * vc->vc_font.width; count -= cnt; - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); } } @@ -394,8 +392,6 @@ static void putcs_aligned(struct vc_data *vc, struct fb_info *info, info->fbops->fb_imageblit(info, image); image->dx += cnt * vc->vc_font.width; count -= cnt; - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); } } @@ -466,8 +462,6 @@ static void accel_putc(struct vc_data *vc, struct fb_info *info, move_buf_aligned(info, dst, src, pitch, width, image.height); info->fbops->fb_imageblit(info, &image); - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); } void accel_putcs(struct vc_data *vc, struct fb_info *info, diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 4dea35376d2c..9fa0f4b9a38e 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -464,23 +464,32 @@ void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, */ u32 fb_get_buffer_offset(struct fb_info *info, u32 size) { - u32 align = info->pixmap.buf_align - 1; - u32 offset, count = 1000; + struct fb_pixmap *buf = &info->pixmap; + u32 align = buf->buf_align - 1, offset; - spin_lock(&info->pixmap.lock); - offset = info->pixmap.offset + align; + /* If IO mapped, we need to sync before access, no sharing of + * the pixmap is done + */ + if (buf->flags & FB_PIXMAP_IO) { + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + return 0; + } + + /* See if we fit in the remaining pixmap space */ + offset = buf->offset + align; offset &= ~align; - if (offset + size > info->pixmap.size) { - while (atomic_read(&info->pixmap.count) && count--); - if (info->fbops->fb_sync && - info->pixmap.flags & FB_PIXMAP_SYNC) + if (offset + size > buf->size) { + /* We do not fit. In order to be able to re-use the buffer, + * we must ensure no asynchronous DMA'ing or whatever operation + * is in progress, we sync for that. + */ + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) info->fbops->fb_sync(info); offset = 0; } - info->pixmap.offset = offset + size; - atomic_inc(&info->pixmap.count); - smp_mb__after_atomic_inc(); - spin_unlock(&info->pixmap.lock); + buf->offset = offset + size; + return offset; } @@ -733,8 +742,6 @@ int fb_show_logo(struct fb_info *info) x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { image.dx = x; info->fbops->fb_imageblit(info, &image); - //atomic_dec(&info->pixmap.count); - //smp_mb__after_atomic_dec(); } if (palette != NULL) @@ -1254,7 +1261,6 @@ register_framebuffer(struct fb_info *fb_info) fb_info->pixmap.outbuf = sys_outbuf; if (fb_info->pixmap.inbuf == NULL) fb_info->pixmap.inbuf = sys_inbuf; - spin_lock_init(&fb_info->pixmap.lock); registered_fb[i] = fb_info; diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c index 7ac5a923542a..85fde8f50857 100644 --- a/drivers/video/softcursor.c +++ b/drivers/video/softcursor.c @@ -74,8 +74,6 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) info->cursor.image.data = dst; info->fbops->fb_imageblit(info, &info->cursor.image); - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); return 0; } diff --git a/include/linux/fb.h b/include/linux/fb.h index b4a8f5c48312..32d119d0d0ea 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -363,8 +363,6 @@ struct fb_pixmap { /* access methods */ void (*outbuf)(u8 *dst, u8 *addr, unsigned int size); u8 (*inbuf) (u8 *addr); - spinlock_t lock; /* spinlock */ - atomic_t count; }; /* -- cgit v1.2.3 From f8048030ca79c46fdd9ce3e909972d4099aa8e8c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 14 Feb 2004 17:33:19 -0800 Subject: [PATCH] fbdev state management This adds some "state" information for power management to fbdev's, along with a notifier mecanism to inform clients of state changes. It also "uses" this mecanism in the function fb_set_suspend() which was an empty placeholder previously, and "shields" various places that access the HW when state isn't running. (It's best to not call them in the first place, but the current state of fbcon makes that _very_ difficult) --- drivers/video/aty/radeon_accel.c | 8 +++---- drivers/video/cfbcopyarea.c | 3 +++ drivers/video/cfbfillrect.c | 3 +++ drivers/video/cfbimgblt.c | 3 +++ drivers/video/console/fbcon.c | 10 ++++++-- drivers/video/fbmem.c | 49 ++++++++++++++++++++++++++++++++++++++-- drivers/video/softcursor.c | 3 +++ include/linux/fb.h | 21 +++++++++++++++++ 8 files changed, 92 insertions(+), 8 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c index aefff282443c..c662e35c416f 100644 --- a/drivers/video/aty/radeon_accel.c +++ b/drivers/video/aty/radeon_accel.c @@ -28,7 +28,7 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) struct fb_fillrect modded; int vxres, vyres; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return; if (radeon_accel_disabled()) { cfb_fillrect(info, region); @@ -81,7 +81,7 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) modded.width = area->width; modded.height = area->height; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return; if (radeon_accel_disabled()) { cfb_copyarea(info, area); @@ -108,7 +108,7 @@ void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct radeonfb_info *rinfo = info->par; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return; radeon_engine_idle(); @@ -119,7 +119,7 @@ int radeonfb_sync(struct fb_info *info) { struct radeonfb_info *rinfo = info->par; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return 0; radeon_engine_idle(); diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 4bbc67bc301f..9c32d2b40bea 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -346,6 +346,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) int dst_idx = 0, src_idx = 0, rev_copy = 0; unsigned long *dst = NULL, *src = NULL; + if (p->state != FBINFO_STATE_RUNNING) + return; + /* We want rotation but lack hardware to do it for us. */ if (!p->fbops->fb_rotate && p->var.rotate) { } diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 5ff34e12a940..20f3acfd8807 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -367,6 +367,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) unsigned long *dst; int dst_idx, left; + if (p->state != FBINFO_STATE_RUNNING) + return; + /* We want rotation but lack hardware to do it for us. */ if (!p->fbops->fb_rotate && p->var.rotate) { } diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 768b0ff72e3b..31da88e329b6 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -275,6 +275,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) int x2, y2, vxres, vyres; u8 *dst1; + if (p->state != FBINFO_STATE_RUNNING) + return; + vxres = p->var.xres_virtual; vyres = p->var.yres_virtual; /* diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index c2d6237f7f09..d5842613e3d5 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -195,8 +195,8 @@ static void fb_flashcursor(void *private) { struct fb_info *info = (struct fb_info *) private; - /* Test to see if the cursor is erased but still on */ - if (!info || (info->cursor.rop == ROP_COPY)) + if (!info || info->state != FBINFO_STATE_RUNNING || + info->cursor.rop == ROP_COPY) return; acquire_console_sem(); info->cursor.enable ^= 1; @@ -939,6 +939,8 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, if (!info->fbops->fb_blank && console_blanked) return; + if (info->state != FBINFO_STATE_RUNNING) + return; if (!height || !width) return; @@ -963,6 +965,8 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) if (!info->fbops->fb_blank && console_blanked) return; + if (info->state != FBINFO_STATE_RUNNING) + return; if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; @@ -978,6 +982,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, if (!info->fbops->fb_blank && console_blanked) return; + if (info->state != FBINFO_STATE_RUNNING) + return; if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 9fa0f4b9a38e..d5e5edbea826 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -396,6 +396,7 @@ extern const char *global_mode_option; static initcall_t pref_init_funcs[FB_MAX]; static int num_pref_init_funcs __initdata = 0; +static struct notifier_block *fb_notifier_list; struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; @@ -695,8 +696,8 @@ int fb_show_logo(struct fb_info *info) struct fb_image image; int x; - /* Return if the frame buffer is not mapped */ - if (fb_logo.logo == NULL) + /* Return if the frame buffer is not mapped or suspended */ + if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) return 0; image.depth = fb_logo.depth; @@ -788,6 +789,9 @@ fb_read(struct file *file, char *buf, size_t count, loff_t *ppos) if (!info || ! info->screen_base) return -ENODEV; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + if (info->fbops->fb_read) return info->fbops->fb_read(file, buf, count, ppos); @@ -823,6 +827,9 @@ fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos) if (!info || !info->screen_base) return -ENODEV; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + if (info->fbops->fb_write) return info->fbops->fb_write(file, buf, count, ppos); @@ -949,6 +956,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) fb_pan_display(info, &info->var); fb_set_cmap(&info->cmap, 1, info); + + notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info); } } return 0; @@ -1297,8 +1306,42 @@ unregister_framebuffer(struct fb_info *fb_info) return 0; } +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return notifier_chain_register(&fb_notifier_list, nb); +} + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return notifier_chain_unregister(&fb_notifier_list, nb); +} + +/** + * fb_set_suspend - low level driver signals suspend + * @info: framebuffer affected + * @state: 0 = resuming, !=0 = suspending + * + * This is meant to be used by low level drivers to + * signal suspend/resume to the core & clients. + * It must be called with the console semaphore held + */ void fb_set_suspend(struct fb_info *info, int state) { + if (state) { + notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, info); + info->state = FBINFO_STATE_SUSPENDED; + } else { + info->state = FBINFO_STATE_RUNNING; + notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, info); + } } /** @@ -1415,5 +1458,7 @@ EXPORT_SYMBOL(fb_get_buffer_offset); EXPORT_SYMBOL(move_buf_unaligned); EXPORT_SYMBOL(move_buf_aligned); EXPORT_SYMBOL(fb_set_suspend); +EXPORT_SYMBOL(fb_register_client); +EXPORT_SYMBOL(fb_unregister_client); MODULE_LICENSE("GPL"); diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c index 85fde8f50857..2bd307452c80 100644 --- a/drivers/video/softcursor.c +++ b/drivers/video/softcursor.c @@ -48,6 +48,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) info->cursor.image.depth = cursor->image.depth; } + if (info->state != FBINFO_STATE_RUNNING) + return 0; + s_pitch = (info->cursor.image.width + 7) >> 3; dsize = s_pitch * info->cursor.image.height; d_pitch = (s_pitch + scan_align) & ~scan_align; diff --git a/include/linux/fb.h b/include/linux/fb.h index 32d119d0d0ea..574808f1450d 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -339,6 +339,24 @@ struct fb_info; struct device; struct file; +/* + * Register/unregister for framebuffer events + */ + +/* The resolution of the passed in fb_info about to change */ +#define FB_EVENT_MODE_CHANGE 0x01 +/* The display on this fb_info is beeing suspended, no access to the + * framebuffer is allowed any more after that call returns + */ +#define FB_EVENT_SUSPEND 0x02 +/* The display on this fb_info was resumed, you can restore the display + * if you own it + */ +#define FB_EVENT_RESUME 0x03 + +extern int fb_register_client(struct notifier_block *nb); +extern int fb_unregister_client(struct notifier_block *nb); + /* * Pixmap structure definition * @@ -447,6 +465,9 @@ struct fb_info { struct vc_data *display_fg; /* Console visible on this display */ int currcon; /* Current VC. */ void *pseudo_palette; /* Fake palette of 16 colors */ +#define FBINFO_STATE_RUNNING 0 +#define FBINFO_STATE_SUSPENDED 1 + u32 state; /* Hardware state i.e suspend */ /* From here on everything is device dependent */ void *par; }; -- cgit v1.2.3