diff options
author | Helge Deller <deller@gmx.de> | 2006-12-13 00:35:55 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-13 09:05:55 -0800 |
commit | 0743b86800cf1dfbf96df4a438938127bbe4476c (patch) | |
tree | 49a9807cdf0fcefb4d4d1652b8d9515766535d21 | |
parent | 3161986224a3faa8ccca3e665b7404d81e7ee3cf (diff) | |
download | linux-0743b86800cf1dfbf96df4a438938127bbe4476c.tar.gz linux-0743b86800cf1dfbf96df4a438938127bbe4476c.tar.bz2 linux-0743b86800cf1dfbf96df4a438938127bbe4476c.zip |
[PATCH] sstfb: add sysfs interface
Modify the sstfb (Voodoo1/2) driver:
- fix a memleak when removing the sstfb module
- fix sstfb to use the fbdev default videomode database
- add module option "mode_option" to set initial screen mode
- add sysfs-interface to turn VGA-passthrough on/off via
/sys/class/graphics/fbX/vgapass
- remove old debug functions from ioctl interface
Signed-off-by: Helge Deller <deller@gmx.de>
Acked-By: James Simmons <jsimmons@infradead.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/video/sstfb.c | 335 | ||||
-rw-r--r-- | include/video/sstfb.h | 13 |
2 files changed, 114 insertions, 234 deletions
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 711cb11d6eb3..59cd1e750f30 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -21,6 +21,11 @@ * Remove never finished and bogus 24/32bit support * Clean up macro abuse * Minor tidying for format. + * 12/2006 Helge Deller <deller@gmx.de> + * add /sys/class/graphics/fbX/vgapass sysfs-interface + * add module option "mode_option" to set initial screen mode + * use fbdev default videomode database + * remove debug functions from ioctl */ /* @@ -65,19 +70,10 @@ * * sstfb specific ioctls: * toggle vga (0x46db) : toggle vga_pass_through - * fill fb (0x46dc) : fills fb - * test disp (0x46de) : draws a test image */ #undef SST_DEBUG -/* - Default video mode . - 0 800x600@60 took from glide - 1 640x480@75 took from glide - 2 1024x768@76 std fb.mode - 3 640x480@60 glide default */ -#define DEFAULT_MODE 3 /* * Includes @@ -92,20 +88,24 @@ #include <linux/init.h> #include <linux/slab.h> #include <asm/io.h> -#include <asm/ioctl.h> #include <asm/uaccess.h> #include <video/sstfb.h> /* initialized by setup */ -static int vgapass; /* enable Vga passthrough cable */ +static int vgapass; /* enable VGA passthrough cable */ static int mem; /* mem size in MB, 0 = autodetect */ static int clipping = 1; /* use clipping (slower, safer) */ static int gfxclk; /* force FBI freq in Mhz . Dangerous */ static int slowpci; /* slow PCI settings */ -static char *mode_option __devinitdata; +/* + Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60 +*/ +#define DEFAULT_VIDEO_MODE "640x480@60" + +static char *mode_option __devinitdata = DEFAULT_VIDEO_MODE; enum { ID_VOODOO1 = 0, @@ -119,48 +119,11 @@ static struct sst_spec voodoo_spec[] __devinitdata = { { .name = "Voodoo2", .default_gfx_clock = 75000, .max_gfxclk = 85 }, }; -static struct fb_var_screeninfo sstfb_default = -#if ( DEFAULT_MODE == 0 ) - { /* 800x600@60, 16 bpp .borowed from glide/sst1/include/sst1init.h */ - 800, 600, 800, 600, 0, 0, 16, 0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, - 25000, 86, 41, 23, 1, 127, 4, - 0, FB_VMODE_NONINTERLACED }; -#elif ( DEFAULT_MODE == 1 ) - {/* 640x480@75, 16 bpp .borowed from glide/sst1/include/sst1init.h */ - 640, 480, 640, 480, 0, 0, 16, 0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, - 31746, 118, 17, 16, 1, 63, 3, - 0, FB_VMODE_NONINTERLACED }; -#elif ( DEFAULT_MODE == 2 ) - { /* 1024x768@76 took from my /etc/fb.modes */ - 1024, 768, 1024, 768,0, 0, 16,0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, - 11764, 208, 8, 36, 16, 120, 3 , - 0, FB_VMODE_NONINTERLACED }; -#elif ( DEFAULT_MODE == 3 ) - { /* 640x480@60 , 16bpp glide default ?*/ - 640, 480, 640, 480, 0, 0, 16, 0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, - 39721 , 38, 26 , 25 ,18 , 96 ,2, - 0, FB_VMODE_NONINTERLACED }; -#elif - #error "Invalid DEFAULT_MODE value !" -#endif - /* * debug functions */ -static void sstfb_drawdebugimage(struct fb_info *info); -static int sstfb_dump_regs(struct fb_info *info); - - #if (SST_DEBUG_REG > 0) static void sst_dbg_print_read_reg(u32 reg, u32 val) { const char *regname; @@ -726,51 +689,77 @@ static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, return 0; } -static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) +static void sstfb_setvgapass( struct fb_info *info, int enable ) { struct sstfb_par *par = info->par; struct pci_dev *sst_dev = par->dev; - u32 fbiinit0, tmp, val; - u_long p; + u32 fbiinit0, tmp; + + enable = enable ? 1:0; + if (par->vgapass == enable) + return; + par->vgapass = enable; + + pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp); + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, + tmp | PCI_EN_INIT_WR ); + fbiinit0 = sst_read (FBIINIT0); + if (par->vgapass) { + sst_write(FBIINIT0, fbiinit0 & ~DIS_VGA_PASSTHROUGH); + printk(KERN_INFO "fb%d: Enabling VGA pass-through\n", info->node ); + } else { + sst_write(FBIINIT0, fbiinit0 | DIS_VGA_PASSTHROUGH); + printk(KERN_INFO "fb%d: Disabling VGA pass-through\n", info->node ); + } + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp); +} + +static ssize_t store_vgapass(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *info = dev_get_drvdata(device); + char ** last = NULL; + int val; + + val = simple_strtoul(buf, last, 0); + sstfb_setvgapass(info, val); + + return count; +} + +static ssize_t show_vgapass(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *info = dev_get_drvdata(device); + struct sstfb_par *par = info->par; + return snprintf(buf, PAGE_SIZE, "%d\n", par->vgapass); +} + +static struct device_attribute device_attrs[] = { + __ATTR(vgapass, S_IRUGO|S_IWUSR, show_vgapass, store_vgapass) + }; + +static int sstfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct sstfb_par *par; + u32 val; switch (cmd) { - - /* dump current FBIINIT values to system log */ - case _IO('F', 0xdb): /* 0x46db */ - return sstfb_dump_regs(info); - - /* fills lfb with #arg pixels */ - case _IOW('F', 0xdc, u32): /* 0x46dc */ + /* set/get VGA pass_through mode */ + case SSTFB_SET_VGAPASS: if (copy_from_user(&val, (void __user *)arg, sizeof(val))) return -EFAULT; - if (val > info->fix.smem_len) - val = info->fix.smem_len; - for (p = 0 ; p < val; p += 2) - writew(p >> 6, info->screen_base + p); + sstfb_setvgapass(info, val); return 0; - - /* change VGA pass_through mode */ - case _IOW('F', 0xdd, u32): /* 0x46dd */ - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) + case SSTFB_GET_VGAPASS: + par = info->par; + val = par->vgapass; + if (copy_to_user((void __user *)arg, &val, sizeof(val))) return -EFAULT; - pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp); - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, - tmp | PCI_EN_INIT_WR ); - fbiinit0 = sst_read (FBIINIT0); - if (val) - sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH); - else - sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH); - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp); - return 0; - - /* draw test image */ - case _IO('F', 0xde): /* 0x46de */ - f_dprintk("test color display at %d bpp\n", - info->var.bits_per_pixel); - sstfb_drawdebugimage(info); return 0; } + return -EINVAL; } @@ -804,6 +793,7 @@ static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) /* * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only */ +#if 0 static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct sstfb_par *par = info->par; @@ -825,6 +815,7 @@ static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) ); sst_wait_idle(); } +#endif @@ -1156,6 +1147,7 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par) struct pll_timing gfx_timings; struct sst_spec *spec; int Fout; + int gfx_clock; spec = &voodoo_spec[par->type]; f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " @@ -1196,15 +1188,15 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par) } /* set graphic clock */ - par->gfx_clock = spec->default_gfx_clock; + gfx_clock = spec->default_gfx_clock; if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk); - par->gfx_clock = gfxclk *1000; + gfx_clock = gfxclk *1000; } else if (gfxclk) { printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk); } - sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings); + sst_calc_pll(gfx_clock, &Fout, &gfx_timings); par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); /* disable fbiinit remap */ @@ -1215,10 +1207,11 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par) fbiinit0 = FBIINIT0_DEFAULT; fbiinit1 = FBIINIT1_DEFAULT; fbiinit4 = FBIINIT4_DEFAULT; - if (vgapass) - fbiinit0 &= ~EN_VGA_PASSTHROUGH; + par->vgapass = vgapass; + if (par->vgapass) + fbiinit0 &= ~DIS_VGA_PASSTHROUGH; else - fbiinit0 |= EN_VGA_PASSTHROUGH; + fbiinit0 |= DIS_VGA_PASSTHROUGH; if (slowpci) { fbiinit1 |= SLOW_PCI_WRITES; fbiinit4 |= SLOW_PCI_READS; @@ -1267,7 +1260,7 @@ static void __devexit sst_shutdown(struct fb_info *info) /* TODO maybe shutdown the dac, vrefresh and so on... */ pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); - sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | EN_VGA_PASSTHROUGH); + sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | DIS_VGA_PASSTHROUGH); pci_write_config_dword(dev, PCI_VCLK_DISABLE,0); /* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct * from start ? */ @@ -1278,8 +1271,7 @@ static void __devexit sst_shutdown(struct fb_info *info) /* * Interface to the world */ -#ifndef MODULE -static int __init sstfb_setup(char *options) +static int __devinit sstfb_setup(char *options) { char *this_opt; @@ -1312,7 +1304,7 @@ static int __init sstfb_setup(char *options) } return 0; } -#endif + static struct fb_ops sstfb_ops = { .owner = THIS_MODULE, @@ -1416,15 +1408,10 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, */ fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */ - if ( mode_option && - fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16)) { - printk(KERN_ERR "sstfb: can't set supplied video mode. Using default\n"); - info->var = sstfb_default; - } else - info->var = sstfb_default; + fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); if (sstfb_check_var(&info->var, info)) { - printk(KERN_ERR "sstfb: invalid default video mode.\n"); + printk(KERN_ERR "sstfb: invalid video mode.\n"); goto fail; } @@ -1442,10 +1429,11 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, goto fail; } - if (1) /* set to 0 to see an initial bitmap instead */ - sstfb_clear_screen(info); - else - sstfb_drawdebugimage(info); + sstfb_clear_screen(info); + + if (device_create_file(info->dev, &device_attrs[0])) + printk(KERN_WARNING "sstfb: can't create sysfs entry.\n"); + printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n", info->node, fix->id, info->screen_base); @@ -1453,6 +1441,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, return 0; fail: + fb_dealloc_cmap(&info->cmap); iounmap(info->screen_base); fail_fb_remap: iounmap(par->mmio_vbase); @@ -1473,21 +1462,23 @@ static void __devexit sstfb_remove(struct pci_dev *pdev) info = pci_get_drvdata(pdev); par = info->par; + device_remove_file(info->dev, &device_attrs[0]); sst_shutdown(info); - unregister_framebuffer(info); iounmap(info->screen_base); iounmap(par->mmio_vbase); release_mem_region(info->fix.smem_start, 0x400000); release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + fb_dealloc_cmap(&info->cmap); + unregister_framebuffer(info); framebuffer_release(info); } -static struct pci_device_id sstfb_id_tbl[] = { - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 }, - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 }, +static const struct pci_device_id sstfb_id_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO ), + .driver_data = ID_VOODOO1, }, + { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2), + .driver_data = ID_VOODOO2, }, { 0 }, }; @@ -1501,142 +1492,23 @@ static struct pci_driver sstfb_driver = { static int __devinit sstfb_init(void) { -#ifndef MODULE char *option = NULL; if (fb_get_options("sstfb", &option)) return -ENODEV; sstfb_setup(option); -#endif + return pci_register_driver(&sstfb_driver); } -#ifdef MODULE static void __devexit sstfb_exit(void) { pci_unregister_driver(&sstfb_driver); } -#endif -/* - * testing and debugging functions - */ - -static int sstfb_dump_regs(struct fb_info *info) -{ -#ifdef SST_DEBUG - static struct { u32 reg ; const char *reg_name;} pci_regs[] = { - { PCI_INIT_ENABLE, "initenable"}, - { PCI_VCLK_ENABLE, "enable vclk"}, - { PCI_VCLK_DISABLE, "disable vclk"}, - }; - - static struct { u32 reg ; const char *reg_name;} sst_regs[] = { - {FBIINIT0,"fbiinit0"}, - {FBIINIT1,"fbiinit1"}, - {FBIINIT2,"fbiinit2"}, - {FBIINIT3,"fbiinit3"}, - {FBIINIT4,"fbiinit4"}, - {FBIINIT5,"fbiinit5"}, - {FBIINIT6,"fbiinit6"}, - {FBIINIT7,"fbiinit7"}, - {LFBMODE,"lfbmode"}, - {FBZMODE,"fbzmode"}, - }; - - const int pci_s = ARRAY_SIZE(pci_regs); - const int sst_s = ARRAY_SIZE(sst_regs); - struct sstfb_par *par = info->par; - struct pci_dev *dev = par->dev; - u32 pci_res[pci_s]; - u32 sst_res[sst_s]; - int i; - - for (i=0; i<pci_s; i++) { - pci_read_config_dword(dev, pci_regs[i].reg, &pci_res[i]); - } - for (i=0; i<sst_s; i++) { - sst_res[i] = sst_read(sst_regs[i].reg); - } - - dprintk("hardware register dump:\n"); - for (i=0; i<pci_s; i++) { - dprintk("%s %0#10x\n", pci_regs[i].reg_name, pci_res[i]); - } - for (i=0; i<sst_s; i++) { - dprintk("%s %0#10x\n", sst_regs[i].reg_name, sst_res[i]); - } - return 0; -#else - return -EINVAL; -#endif -} - -static void sstfb_fillrect_softw( struct fb_info *info, const struct fb_fillrect *rect) -{ - u8 __iomem *fbbase_virt = info->screen_base; - int x, y, w = info->var.bits_per_pixel == 16 ? 2 : 4; - u32 color = rect->color, height = rect->height; - u8 __iomem *p; - - if (w==2) color |= color<<16; - for (y=rect->dy; height; y++, height--) { - p = fbbase_virt + y*info->fix.line_length + rect->dx*w; - x = rect->width; - if (w==2) x>>=1; - while (x) { - writel(color, p); - p += 4; - x--; - } - } -} - -static void sstfb_drawrect_XY( struct fb_info *info, int x, int y, - int w, int h, int color, int hwfunc) -{ - struct fb_fillrect rect; - rect.dx = x; - rect.dy = y; - rect.height = h; - rect.width = w; - rect.color = color; - rect.rop = ROP_COPY; - if (hwfunc) - sstfb_fillrect(info, &rect); - else - sstfb_fillrect_softw(info, &rect); -} - -/* print some squares on the fb */ -static void sstfb_drawdebugimage(struct fb_info *info) -{ - static int idx; - - /* clear screen */ - sstfb_clear_screen(info); - - idx = (idx+1) & 1; - - /* white rect */ - sstfb_drawrect_XY(info, 0, 0, 50, 50, 0xffff, idx); - - /* blue rect */ - sstfb_drawrect_XY(info, 50, 50, 50, 50, 0x001f, idx); - - /* green rect */ - sstfb_drawrect_XY(info, 100, 100, 80, 80, 0x07e0, idx); - - /* red rect */ - sstfb_drawrect_XY(info, 250, 250, 120, 100, 0xf800, idx); -} - module_init(sstfb_init); - -#ifdef MODULE module_exit(sstfb_exit); -#endif MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>"); MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards"); @@ -1652,3 +1524,6 @@ module_param(gfxclk, int, 0); MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)"); module_param(slowpci, bool, 0); MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode (default=" DEFAULT_VIDEO_MODE ")"); + diff --git a/include/video/sstfb.h b/include/video/sstfb.h index 5dbf5e7e50a8..baa163f770ab 100644 --- a/include/video/sstfb.h +++ b/include/video/sstfb.h @@ -119,7 +119,7 @@ #define BACKPORCH 0x0208 #define VIDEODIMENSIONS 0x020c #define FBIINIT0 0x0210 /* misc+fifo controls */ -# define EN_VGA_PASSTHROUGH BIT(0) +# define DIS_VGA_PASSTHROUGH BIT(0) # define FBI_RESET BIT(1) # define FIFO_RESET BIT(2) #define FBIINIT1 0x0214 /* PCI + video controls */ @@ -251,7 +251,7 @@ # define DACREG_ICS_CLK1_A 0 /* bit4 */ /* sst default init registers */ -#define FBIINIT0_DEFAULT EN_VGA_PASSTHROUGH +#define FBIINIT0_DEFAULT DIS_VGA_PASSTHROUGH #define FBIINIT1_DEFAULT \ ( \ @@ -296,6 +296,11 @@ * */ +/* ioctl to enable/disable VGA passthrough */ +#define SSTFB_SET_VGAPASS _IOW('F', 0xdd, __u32) +#define SSTFB_GET_VGAPASS _IOR('F', 0xdd, __u32) + + /* used to know witch clock to set */ enum { VID_CLOCK=0, @@ -317,7 +322,7 @@ struct pll_timing { }; struct dac_switch { - char * name; + const char *name; int (*detect) (struct fb_info *info); int (*set_pll) (struct fb_info *info, const struct pll_timing *t, const int clock); void (*set_vidmod) (struct fb_info *info, const int bpp); @@ -345,7 +350,7 @@ struct sstfb_par { struct pci_dev *dev; int type; u8 revision; - int gfx_clock; /* status */ + u8 vgapass; /* VGA pass through: 1=enabled, 0=disabled */ }; #endif /* _SSTFB_H_ */ |