The patch titled fbdev driver for S3 Trio/Virge, updated has been removed from the -mm tree. Its filename was fbdev-driver-for-s3-trio-virge-update-2.patch This patch was dropped because it was folded into fbdev-driver-for-s3-trio-virge.patch ------------------------------------------------------ Subject: fbdev driver for S3 Trio/Virge, updated From: Ondrej Zajicek <santiago@xxxxxxxxxxxxx> This is version 3. There are some minor modifications from version 2 (mostly coding style cleanups). Signed-off-by: Ondrej Zajicek <santiago@xxxxxxxxxxxxx> Cc: James Simmons <jsimmons@xxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- drivers/video/s3fb.c | 435 ++++++++++++++++++++------------------ drivers/video/svgalib.c | 86 ++++--- include/linux/svga.h | 6 3 files changed, 284 insertions(+), 243 deletions(-) diff -puN drivers/video/s3fb.c~fbdev-driver-for-s3-trio-virge-update-2 drivers/video/s3fb.c --- a/drivers/video/s3fb.c~fbdev-driver-for-s3-trio-virge-update-2 +++ a/drivers/video/s3fb.c @@ -1,7 +1,7 @@ /* * linux/drivers/video/s3fb.c -- Frame buffer device driver for S3 Trio/Virge * - * Copyright (c) 2006 Ondrej Zajicek <santiago@xxxxxxxxxxxxx> + * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@xxxxxxxxxxxxx> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -32,12 +32,11 @@ #endif struct s3fb_info { - struct fb_info fb; - int chip, rev, mclk_freq; int mtrr_reg; struct vgastate state; - atomic_t ref_count; + struct mutex open_lock; + unsigned int ref_count; u32 pseudo_palette[16]; }; @@ -141,9 +140,8 @@ static int mtrr = 1; static int fasttext = 1; -#ifdef MODULE -MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@xxxxxxxxxxxxx>"); +MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@xxxxxxxxxxxxx>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge"); @@ -158,7 +156,6 @@ MODULE_PARM_DESC(mtrr, "Enable write-com module_param(fasttext, int, 0644); MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)"); -#endif /* ------------------------------------------------------------------------- */ @@ -209,7 +206,9 @@ static struct fb_tile_ops s3fb_fast_tile /* image data is MSB-first, fb structure is MSB-first too */ static inline u32 expand_color(u32 c) -{ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF; } +{ + return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF; +} /* s3fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */ static void s3fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image) @@ -223,7 +222,7 @@ static void s3fb_iplan_imageblit(struct int x, y; src1 = image->data; - dst1 = info->screen_base + (image->dy * info->fix.line_length) + dst1 = info->screen_base + (image->dy * info->fix.line_length) + ((image->dx / 8) * 4); for (y = 0; y < image->height; y++) { @@ -248,7 +247,7 @@ static void s3fb_iplan_fillrect(struct f u32 __iomem *dst; int x, y; - dst1 = info->screen_base + (rect->dy * info->fix.line_length) + dst1 = info->screen_base + (rect->dy * info->fix.line_length) + ((rect->dx / 8) * 4); for (y = 0; y < rect->height; y++) { @@ -258,7 +257,6 @@ static void s3fb_iplan_fillrect(struct f } dst1 += info->fix.line_length; } - } @@ -281,7 +279,7 @@ static void s3fb_cfb4_imageblit(struct f int x, y; src1 = image->data; - dst1 = info->screen_base + (image->dy * info->fix.line_length) + dst1 = info->screen_base + (image->dy * info->fix.line_length) + ((image->dx / 8) * 4); for (y = 0; y < image->height; y++) { @@ -295,7 +293,6 @@ static void s3fb_cfb4_imageblit(struct f src1 += image->width / 8; dst1 += info->fix.line_length; } - } static void s3fb_imageblit(struct fb_info *info, const struct fb_image *image) @@ -354,10 +351,10 @@ static void s3_set_pixclock(struct fb_in static int s3fb_open(struct fb_info *info, int user) { - struct s3fb_info *par = (struct s3fb_info *) info; - unsigned int count = atomic_read(&(par->ref_count)); + struct s3fb_info *par = info->par; - if (!count) { + mutex_lock(&(par->open_lock)); + if (par->ref_count == 0) { memset(&(par->state), 0, sizeof(struct vgastate)); par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; par->state.num_crtc = 0x70; @@ -365,7 +362,8 @@ static int s3fb_open(struct fb_info *inf save_vga(&(par->state)); } - atomic_inc(&(par->ref_count)); + par->ref_count++; + mutex_unlock(&(par->open_lock)); return 0; } @@ -374,16 +372,19 @@ static int s3fb_open(struct fb_info *inf static int s3fb_release(struct fb_info *info, int user) { - struct s3fb_info *par = (struct s3fb_info *) info; - unsigned int count = atomic_read(&(par->ref_count)); + struct s3fb_info *par = info->par; - if (!count) + mutex_lock(&(par->open_lock)); + if (par->ref_count == 0) { + mutex_unlock(&(par->open_lock)); return -EINVAL; + } - if (count == 1) + if (par->ref_count == 1) restore_vga(&(par->state)); - atomic_dec(&(par->ref_count)); + par->ref_count--; + mutex_unlock(&(par->open_lock)); return 0; } @@ -392,7 +393,7 @@ static int s3fb_release(struct fb_info * static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - struct s3fb_info *par = (struct s3fb_info *) info; + struct s3fb_info *par = info->par; int rv, mem, step; /* Find appropriate format */ @@ -418,7 +419,8 @@ static int s3fb_check_var(struct fb_var_ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; if (mem > info->screen_size) { - printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); + printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", + info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); return -EINVAL; } @@ -436,7 +438,7 @@ static int s3fb_check_var(struct fb_var_ static int s3fb_set_par(struct fb_info *info) { - struct s3fb_info *par = (struct s3fb_info *) info; + struct s3fb_info *par = info->par; u32 value, mode, hmul, offset_value, screen_size, multiplex; u32 bpp = info->var.bits_per_pixel; @@ -526,8 +528,6 @@ static int s3fb_set_par(struct fb_info * /* Disable Streams engine */ svga_wcrt_mask(0x67, 0x00, 0x0C); - - mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix)); /* S3 virge DX hack */ @@ -551,93 +551,93 @@ static int s3fb_set_par(struct fb_info * /* Set mode-specific register values */ switch (mode) { - case 0: - pr_debug("fb%d: text mode\n", info->node); - svga_set_textmode_vga_regs(); - - /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); - - /* Disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + case 0: + pr_debug("fb%d: text mode\n", info->node); + svga_set_textmode_vga_regs(); + + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(0x67, 0x00, 0xF0); + + /* Disable enhanced mode */ + svga_wcrt_mask(0x3A, 0x00, 0x30); + + if (fasttext) { + pr_debug("fb%d: high speed text mode set\n", info->node); + svga_wcrt_mask(0x31, 0x40, 0x40); + } + break; + case 1: + pr_debug("fb%d: 4 bit pseudocolor\n", info->node); + vga_wgfx(NULL, VGA_GFX_MODE, 0x40); + + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(0x67, 0x00, 0xF0); - if (fasttext) { - pr_debug("fb%d: high speed text mode set\n", info->node); - svga_wcrt_mask(0x31, 0x40, 0x40); - } + /* disable enhanced mode */ + svga_wcrt_mask(0x3A, 0x00, 0x30); break; - case 1: - pr_debug("fb%d: 4 bit pseudocolor\n", info->node); - vga_wgfx(NULL, VGA_GFX_MODE, 0x40); + case 2: + pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); - /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(0x67, 0x00, 0xF0); - /* disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + /* disable enhanced mode */ + svga_wcrt_mask(0x3A, 0x00, 0x30); break; - case 2: - pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); - - /* Set additional registers like in 8-bit mode */ + case 3: + pr_debug("fb%d: 8 bit pseudocolor\n", info->node); + if (info->var.pixclock > 20000) { svga_wcrt_mask(0x50, 0x00, 0x30); svga_wcrt_mask(0x67, 0x00, 0xF0); - - /* disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); - break; - case 3: - pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - if (info->var.pixclock > 20000) { - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); - } else { - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x10, 0xF0); - multiplex = 1; - } + } else { + svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(0x67, 0x10, 0xF0); + multiplex = 1; + } break; - case 4: - pr_debug("fb%d: 5/5/5 truecolor\n", info->node); - if (par->chip == CHIP_988_VIRGE_VX) { - if (info->var.pixclock > 20000) - svga_wcrt_mask(0x67, 0x20, 0xF0); - else - svga_wcrt_mask(0x67, 0x30, 0xF0); - } else { - svga_wcrt_mask(0x50, 0x10, 0x30); + case 4: + pr_debug("fb%d: 5/5/5 truecolor\n", info->node); + if (par->chip == CHIP_988_VIRGE_VX) { + if (info->var.pixclock > 20000) + svga_wcrt_mask(0x67, 0x20, 0xF0); + else svga_wcrt_mask(0x67, 0x30, 0xF0); - hmul = 2; - } + } else { + svga_wcrt_mask(0x50, 0x10, 0x30); + svga_wcrt_mask(0x67, 0x30, 0xF0); + hmul = 2; + } break; - case 5: - pr_debug("fb%d: 5/6/5 truecolor\n", info->node); - if (par->chip == CHIP_988_VIRGE_VX) { - if (info->var.pixclock > 20000) - svga_wcrt_mask(0x67, 0x40, 0xF0); - else - svga_wcrt_mask(0x67, 0x50, 0xF0); - } else { - svga_wcrt_mask(0x50, 0x10, 0x30); + case 5: + pr_debug("fb%d: 5/6/5 truecolor\n", info->node); + if (par->chip == CHIP_988_VIRGE_VX) { + if (info->var.pixclock > 20000) + svga_wcrt_mask(0x67, 0x40, 0xF0); + else svga_wcrt_mask(0x67, 0x50, 0xF0); - hmul = 2; - } + } else { + svga_wcrt_mask(0x50, 0x10, 0x30); + svga_wcrt_mask(0x67, 0x50, 0xF0); + hmul = 2; + } break; - case 6: - /* VIRGE VX case */ - pr_debug("fb%d: 8/8/8 truecolor\n", info->node); - svga_wcrt_mask(0x67, 0xD0, 0xF0); + case 6: + /* VIRGE VX case */ + pr_debug("fb%d: 8/8/8 truecolor\n", info->node); + svga_wcrt_mask(0x67, 0xD0, 0xF0); break; - case 7: - pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); - svga_wcrt_mask(0x50, 0x30, 0x30); - svga_wcrt_mask(0x67, 0xD0, 0xF0); + case 7: + pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); + svga_wcrt_mask(0x50, 0x30, 0x30); + svga_wcrt_mask(0x67, 0xD0, 0xF0); break; - default: - printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); - return -EINVAL; + default: + printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); + return -EINVAL; } if (par->chip != CHIP_988_VIRGE_VX) { @@ -651,8 +651,6 @@ static int s3fb_set_par(struct fb_info * (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1, hmul, info->node); - - /* Set interlaced mode start/end register */ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; value = ((value * hmul) / 8) - 5; @@ -672,47 +670,55 @@ static int s3fb_setcolreg(u_int regno, u u_int transp, struct fb_info *fb) { switch (fb->var.bits_per_pixel) { - case 0: - case 4: - if (regno >= 16) return -EINVAL; - - if ((fb->var.bits_per_pixel == 4) && - (fb->var.nonstd == 0)) { - outb(0xF0, VGA_PEL_MSK); - outb(regno*16, VGA_PEL_IW); - } else { - outb(0x0F, VGA_PEL_MSK); - outb(regno, VGA_PEL_IW); - } - outb(red >> 10, VGA_PEL_D); - outb(green >> 10, VGA_PEL_D); - outb(blue >> 10, VGA_PEL_D); - break; - case 8: - if (regno >= 256) return -EINVAL; - outb(0xFF, VGA_PEL_MSK); + case 0: + case 4: + if (regno >= 16) + return -EINVAL; + + if ((fb->var.bits_per_pixel == 4) && + (fb->var.nonstd == 0)) { + outb(0xF0, VGA_PEL_MSK); + outb(regno*16, VGA_PEL_IW); + } else { + outb(0x0F, VGA_PEL_MSK); outb(regno, VGA_PEL_IW); - outb(red >> 10, VGA_PEL_D); - outb(green >> 10, VGA_PEL_D); - outb(blue >> 10, VGA_PEL_D); + } + outb(red >> 10, VGA_PEL_D); + outb(green >> 10, VGA_PEL_D); + outb(blue >> 10, VGA_PEL_D); break; - case 16: - if (regno >= 16) return -EINVAL; - if (fb->var.green.length == 5) - ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); - else if (fb->var.green.length == 6) - ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); - else return -EINVAL; + case 8: + if (regno >= 256) + return -EINVAL; + + outb(0xFF, VGA_PEL_MSK); + outb(regno, VGA_PEL_IW); + outb(red >> 10, VGA_PEL_D); + outb(green >> 10, VGA_PEL_D); + outb(blue >> 10, VGA_PEL_D); break; + case 16: + if (regno >= 16) + return -EINVAL; - case 24: - case 32: - if (regno >= 16) return -EINVAL; - ((u32*)fb->pseudo_palette)[regno] = ((transp & 0xFF00) >> 16 ) | ((blue & 0xFF00) >> 8) | - (green & 0xFF00) | ((red & 0xFF00) << 8); + if (fb->var.green.length == 5) + ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | + ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); + else if (fb->var.green.length == 6) + ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | + ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); + else return -EINVAL; break; - default: + case 24: + case 32: + if (regno >= 16) return -EINVAL; + + ((u32*)fb->pseudo_palette)[regno] = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | + (green & 0xFF00) | ((blue & 0xFF00) >> 8); + break; + default: + return -EINVAL; } return 0; @@ -724,30 +730,30 @@ static int s3fb_setcolreg(u_int regno, u static int s3fb_blank(int blank_mode, struct fb_info *info) { switch (blank_mode) { - case FB_BLANK_UNBLANK: - pr_debug("fb%d: unblank\n", info->node); - svga_wcrt_mask(0x56, 0x00, 0x06); - svga_wseq_mask(0x01, 0x00, 0x20); + case FB_BLANK_UNBLANK: + pr_debug("fb%d: unblank\n", info->node); + svga_wcrt_mask(0x56, 0x00, 0x06); + svga_wseq_mask(0x01, 0x00, 0x20); break; - case FB_BLANK_NORMAL: - pr_debug("fb%d: blank\n", info->node); - svga_wcrt_mask(0x56, 0x00, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + case FB_BLANK_NORMAL: + pr_debug("fb%d: blank\n", info->node); + svga_wcrt_mask(0x56, 0x00, 0x06); + svga_wseq_mask(0x01, 0x20, 0x20); break; - case FB_BLANK_HSYNC_SUSPEND: - pr_debug("fb%d: hsync\n", info->node); - svga_wcrt_mask(0x56, 0x02, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + case FB_BLANK_HSYNC_SUSPEND: + pr_debug("fb%d: hsync\n", info->node); + svga_wcrt_mask(0x56, 0x02, 0x06); + svga_wseq_mask(0x01, 0x20, 0x20); break; - case FB_BLANK_VSYNC_SUSPEND: - pr_debug("fb%d: vsync\n", info->node); - svga_wcrt_mask(0x56, 0x04, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + case FB_BLANK_VSYNC_SUSPEND: + pr_debug("fb%d: vsync\n", info->node); + svga_wcrt_mask(0x56, 0x04, 0x06); + svga_wseq_mask(0x01, 0x20, 0x20); break; - case FB_BLANK_POWERDOWN: - pr_debug("fb%d: sync down\n", info->node); - svga_wcrt_mask(0x56, 0x06, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + case FB_BLANK_POWERDOWN: + pr_debug("fb%d: sync down\n", info->node); + svga_wcrt_mask(0x56, 0x06, 0x06); + svga_wseq_mask(0x01, 0x20, 0x20); break; } @@ -762,8 +768,10 @@ static int s3fb_pan_display(struct fb_va unsigned int offset; /* Validate the offsets */ - if ((var->xoffset + var->xres) > var->xres_virtual) return -EINVAL; - if ((var->yoffset + var->yres) > var->yres_virtual) return -EINVAL; + if ((var->xoffset + var->xres) > var->xres_virtual) + return -EINVAL; + if ((var->yoffset + var->yres) > var->yres_virtual) + return -EINVAL; /* Calculate the offset */ if (var->bits_per_pixel == 0) { @@ -853,43 +861,46 @@ static int __devinit s3_pci_probe(struct /* Ignore secondary VGA device because there is no VGA arbitration */ if (! svga_primary_device(dev)) { - printk(KERN_INFO "s3fb: ignoring secondary device %s\n", pci_name(dev)); + dev_info(&(dev->dev), "ignoring secondary device\n"); return -ENODEV; } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct s3fb_info), NULL); - if (!info) return -ENOMEM; - par = (struct s3fb_info*) info; + if (!info) { + dev_err(&(dev->dev), "cannot allocate memory\n"); + return -ENOMEM; + } + + par = info->par; + mutex_init(&par->open_lock); info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; info->fbops = &s3fb_ops; /* Prepare PCI device */ - rc = pci_enable_device(dev); if (rc < 0) { - printk(KERN_ERR "s3fb: cannot enable PCI device\n"); + dev_err(&(dev->dev), "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "s3fb"); if (rc < 0) { - printk(KERN_ERR "s3fb: cannot reserve framebuffer region\n"); + dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); goto err_request_regions; } - /* Map physical IO memory address into kernel space */ info->fix.smem_start = pci_resource_start(dev, 0); info->fix.smem_len = pci_resource_len(dev, 0); - info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); + /* Map physical IO memory address into kernel space */ + info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - printk(KERN_ERR "s3fb: ioremap for framebuffer failed\n"); - goto err_ioremap; + dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + goto err_iomap; } /* Unlock regs */ @@ -929,19 +940,24 @@ static int __devinit s3_pci_probe(struct info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - printk(KERN_ERR "s3fb: mode %s not found\n", mode); + dev_err(&(dev->dev), "mode %s not found\n", mode); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); - if (rc < 0) goto err_alloc_cmap; + if (rc < 0) { + dev_err(&(dev->dev), "cannot allocate colormap\n"); + goto err_alloc_cmap; + } rc = register_framebuffer(info); - if (rc < 0) goto err_reg_fb; + if (rc < 0) { + dev_err(&(dev->dev), "cannot register framebugger\n"); + goto err_reg_fb; + } printk(KERN_INFO "fb%d: %s on %s, %d MB RAM, %d MHz MCLK\n", info->node, info->fix.id, pci_name(dev), info->fix.smem_len >> 20, (par->mclk_freq + 500) / 1000); @@ -968,8 +984,8 @@ err_reg_fb: fb_dealloc_cmap(&info->cmap); err_alloc_cmap: err_find_mode: - iounmap(info->screen_base); -err_ioremap: + pci_iounmap(dev, info->screen_base); +err_iomap: pci_release_regions(dev); err_request_regions: /* pci_disable_device(dev); */ @@ -984,7 +1000,7 @@ err_enable_device: static void __devexit s3_pci_remove(struct pci_dev *dev) { struct fb_info *info = pci_get_drvdata(dev); - struct s3fb_info *par = (struct s3fb_info *) info; + struct s3fb_info *par = info->par; if (info) { @@ -998,7 +1014,7 @@ static void __devexit s3_pci_remove(stru unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); - iounmap(info->screen_base); + pci_iounmap(dev, info->screen_base); pci_release_regions(dev); /* pci_disable_device(dev); */ @@ -1012,20 +1028,26 @@ static void __devexit s3_pci_remove(stru static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) { struct fb_info *info = pci_get_drvdata(dev); - unsigned int count = atomic_read(&(((struct s3fb_info *) info)->ref_count)); + struct s3fb_info *par = info->par; - printk(KERN_INFO "fb%d: suspend\n", info->node); + dev_info(&(dev->dev), "suspend\n"); + + acquire_console_sem(); + mutex_lock(&(par->open_lock)); - if ((state.event == PM_EVENT_FREEZE) || (!count)) { + if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { + mutex_unlock(&(par->open_lock)); + release_console_sem(); return 0; } - acquire_console_sem(); fb_set_suspend(info, 1); pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); + + mutex_unlock(&(par->open_lock)); release_console_sem(); return 0; @@ -1037,15 +1059,19 @@ static int s3_pci_suspend(struct pci_dev static int s3_pci_resume(struct pci_dev* dev) { struct fb_info *info = pci_get_drvdata(dev); - unsigned int count = atomic_read(&(((struct s3fb_info *) info)->ref_count)); + struct s3fb_info *par = info->par; - printk(KERN_INFO "fb%d: resume\n", info->node); + dev_info(&(dev->dev), "resume\n"); + + acquire_console_sem(); + mutex_lock(&(par->open_lock)); - if (!count) { + if (par->ref_count == 0) { + mutex_unlock(&(par->open_lock)); + release_console_sem(); return 0; } - acquire_console_sem(); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); pci_enable_device(dev); @@ -1053,6 +1079,8 @@ static int s3_pci_resume(struct pci_dev* s3fb_set_par(info); fb_set_suspend(info, 0); + + mutex_unlock(&(par->open_lock)); release_console_sem(); return 0; @@ -1062,19 +1090,19 @@ static int s3_pci_resume(struct pci_dev* /* List of boards that we are trying to support */ static struct pci_device_id s3_devices[] __devinitdata = { - {PCI_VENDOR_ID_S3, 0x8810, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_XXX_TRIO}, - {PCI_VENDOR_ID_S3, 0x8811, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_XXX_TRIO}, - {PCI_VENDOR_ID_S3, 0x8812, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_M65_AURORA64VP}, - {PCI_VENDOR_ID_S3, 0x8814, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_767_TRIO64UVP}, - {PCI_VENDOR_ID_S3, 0x8901, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_XXX_TRIO64V2_DXGX}, - {PCI_VENDOR_ID_S3, 0x8902, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_551_PLATO_PX}, - - {PCI_VENDOR_ID_S3, 0x5631, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_325_VIRGE}, - {PCI_VENDOR_ID_S3, 0x883D, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_988_VIRGE_VX}, - {PCI_VENDOR_ID_S3, 0x8A01, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_XXX_VIRGE_DXGX}, - {PCI_VENDOR_ID_S3, 0x8A10, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_356_VIRGE_GX2}, - {PCI_VENDOR_ID_S3, 0x8A11, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_357_VIRGE_GX2P}, - {PCI_VENDOR_ID_S3, 0x8A12, PCI_ANY_ID,PCI_ANY_ID,0,0, CHIP_359_VIRGE_GX2P}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8810), .driver_data = CHIP_XXX_TRIO}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8811), .driver_data = CHIP_XXX_TRIO}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8812), .driver_data = CHIP_M65_AURORA64VP}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8814), .driver_data = CHIP_767_TRIO64UVP}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8901), .driver_data = CHIP_XXX_TRIO64V2_DXGX}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8902), .driver_data = CHIP_551_PLATO_PX}, + + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x5631), .driver_data = CHIP_325_VIRGE}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x883D), .driver_data = CHIP_988_VIRGE_VX}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A01), .driver_data = CHIP_XXX_VIRGE_DXGX}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, {0, 0, 0, 0, 0, 0, 0} }; @@ -1123,7 +1151,6 @@ static int __init s3fb_setup(char *opti static void __exit s3fb_cleanup(void) { - pr_debug("s3fb: cleaning up\n"); pci_unregister_driver(&s3fb_pci_driver); } @@ -1134,11 +1161,11 @@ static int __init s3fb_init(void) { #ifndef MODULE - char *option = NULL; + char *option = NULL; - if (fb_get_options("s3fb", &option)) - return -ENODEV; - s3fb_setup(option); + if (fb_get_options("s3fb", &option)) + return -ENODEV; + s3fb_setup(option); #endif pr_debug("s3fb: initializing\n"); diff -puN drivers/video/svgalib.c~fbdev-driver-for-s3-trio-virge-update-2 drivers/video/svgalib.c --- a/drivers/video/svgalib.c~fbdev-driver-for-s3-trio-virge-update-2 +++ a/drivers/video/svgalib.c @@ -1,7 +1,7 @@ /* * Common utility functions for VGA-based graphics cards. * - * Copyright (c) 2006 Ondrej Zajicek <santiago@xxxxxxxxxxxxx> + * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@xxxxxxxxxxxxx> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -40,7 +40,7 @@ void svga_wcrt_multi(const struct vga_re } } -/* Write a sequence register value spread across multiple registers */ +/* Write a sequencer register value spread across multiple registers */ void svga_wseq_multi(const struct vga_regset *regset, u32 value) { u8 regval, bitval, bitnum; @@ -313,23 +313,22 @@ void svga_tilecursor(struct fb_info *inf if (cursor -> shape == FB_TILE_CURSOR_NONE) return; - switch (cursor -> shape) - { - case FB_TILE_CURSOR_UNDERLINE: - cs = 0x0d; - break; - case FB_TILE_CURSOR_LOWER_THIRD: - cs = 0x09; - break; - case FB_TILE_CURSOR_LOWER_HALF: - cs = 0x07; - break; - case FB_TILE_CURSOR_TWO_THIRDS: - cs = 0x05; - break; - case FB_TILE_CURSOR_BLOCK: - cs = 0x01; - break; + switch (cursor -> shape) { + case FB_TILE_CURSOR_UNDERLINE: + cs = 0x0d; + break; + case FB_TILE_CURSOR_LOWER_THIRD: + cs = 0x09; + break; + case FB_TILE_CURSOR_LOWER_HALF: + cs = 0x07; + break; + case FB_TILE_CURSOR_TWO_THIRDS: + cs = 0x05; + break; + case FB_TILE_CURSOR_BLOCK: + cs = 0x01; + break; } /* set cursor position */ @@ -345,12 +344,15 @@ void svga_tilecursor(struct fb_info *inf /* - Compute PLL settings (M, N, R) - F_VCO = (F_BASE * M) / N - F_OUT = F_VCO / (2^R) -*/ + * Compute PLL settings (M, N, R) + * F_VCO = (F_BASE * M) / N + * F_OUT = F_VCO / (2^R) + */ -static inline u32 abs_diff(u32 a, u32 b) {return (a > b) ? (a - b) : (b - a);} +static inline u32 abs_diff(u32 a, u32 b) +{ + return (a > b) ? (a - b) : (b - a); +} int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node) { @@ -425,45 +427,57 @@ int svga_check_timings(const struct svga /* Check horizontal total */ value = var->xres + var->left_margin + var->right_margin + var->hsync_len; - if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs)) return -EINVAL; + if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs)) + return -EINVAL; /* Check horizontal display and blank start */ value = var->xres; - if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs)) return -EINVAL; - if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs)) return -EINVAL; + if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs)) + return -EINVAL; + if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs)) + return -EINVAL; /* Check horizontal sync start */ value = var->xres + var->right_margin; - if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs)) return -EINVAL; + if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs)) + return -EINVAL; /* Check horizontal blank end (or length) */ value = var->left_margin + var->right_margin + var->hsync_len; - if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs))) return -EINVAL; + if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs))) + return -EINVAL; /* Check horizontal sync end (or length) */ value = var->hsync_len; - if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs))) return -EINVAL; + if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs))) + return -EINVAL; /* Check vertical total */ value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; - if ((value - 1) >= svga_regset_size(tm->v_total_regs)) return -EINVAL; + if ((value - 1) >= svga_regset_size(tm->v_total_regs)) + return -EINVAL; /* Check vertical display and blank start */ value = var->yres; - if ((value - 1) >= svga_regset_size(tm->v_display_regs)) return -EINVAL; - if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs)) return -EINVAL; + if ((value - 1) >= svga_regset_size(tm->v_display_regs)) + return -EINVAL; + if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs)) + return -EINVAL; /* Check vertical sync start */ value = var->yres + var->lower_margin; - if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs)) return -EINVAL; + if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs)) + return -EINVAL; /* Check vertical blank end (or length) */ value = var->upper_margin + var->lower_margin + var->vsync_len; - if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs))) return -EINVAL; + if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs))) + return -EINVAL; /* Check vertical sync end (or length) */ value = var->vsync_len; - if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs))) return -EINVAL; + if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs))) + return -EINVAL; return 0; } diff -puN include/linux/svga.h~fbdev-driver-for-s3-trio-virge-update-2 include/linux/svga.h --- a/include/linux/svga.h~fbdev-driver-for-s3-trio-virge-update-2 +++ a/include/linux/svga.h @@ -12,9 +12,9 @@ #define VGA_REGSET_END {VGA_REGSET_END_VAL, 0, 0} struct vga_regset { - __u8 regnum; - __u8 lowbit; - __u8 highbit; + u8 regnum; + u8 lowbit; + u8 highbit; }; /* ------------------------------------------------------------------------- */ _ Patches currently in -mm which might be from santiago@xxxxxxxxxxxxx are fbdev-driver-for-s3-trio-virge.patch fbdev-driver-for-s3-trio-virge-update-2.patch fbdev-driver-for-s3-trio-virge-update-2-fix.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html