[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>
This commit is contained in:
parent
3161986224
commit
0743b86800
2 changed files with 114 additions and 234 deletions
|
@ -21,6 +21,11 @@
|
||||||
* Remove never finished and bogus 24/32bit support
|
* Remove never finished and bogus 24/32bit support
|
||||||
* Clean up macro abuse
|
* Clean up macro abuse
|
||||||
* Minor tidying for format.
|
* 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:
|
* sstfb specific ioctls:
|
||||||
* toggle vga (0x46db) : toggle vga_pass_through
|
* toggle vga (0x46db) : toggle vga_pass_through
|
||||||
* fill fb (0x46dc) : fills fb
|
|
||||||
* test disp (0x46de) : draws a test image
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#undef SST_DEBUG
|
#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
|
* Includes
|
||||||
|
@ -92,20 +88,24 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/ioctl.h>
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <video/sstfb.h>
|
#include <video/sstfb.h>
|
||||||
|
|
||||||
|
|
||||||
/* initialized by setup */
|
/* 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 mem; /* mem size in MB, 0 = autodetect */
|
||||||
static int clipping = 1; /* use clipping (slower, safer) */
|
static int clipping = 1; /* use clipping (slower, safer) */
|
||||||
static int gfxclk; /* force FBI freq in Mhz . Dangerous */
|
static int gfxclk; /* force FBI freq in Mhz . Dangerous */
|
||||||
static int slowpci; /* slow PCI settings */
|
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 {
|
enum {
|
||||||
ID_VOODOO1 = 0,
|
ID_VOODOO1 = 0,
|
||||||
|
@ -119,48 +119,11 @@ static struct sst_spec voodoo_spec[] __devinitdata = {
|
||||||
{ .name = "Voodoo2", .default_gfx_clock = 75000, .max_gfxclk = 85 },
|
{ .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
|
* debug functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void sstfb_drawdebugimage(struct fb_info *info);
|
|
||||||
static int sstfb_dump_regs(struct fb_info *info);
|
|
||||||
|
|
||||||
|
|
||||||
#if (SST_DEBUG_REG > 0)
|
#if (SST_DEBUG_REG > 0)
|
||||||
static void sst_dbg_print_read_reg(u32 reg, u32 val) {
|
static void sst_dbg_print_read_reg(u32 reg, u32 val) {
|
||||||
const char *regname;
|
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;
|
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 sstfb_par *par = info->par;
|
||||||
struct pci_dev *sst_dev = par->dev;
|
struct pci_dev *sst_dev = par->dev;
|
||||||
u32 fbiinit0, tmp, val;
|
u32 fbiinit0, tmp;
|
||||||
u_long p;
|
|
||||||
|
|
||||||
switch (cmd) {
|
enable = enable ? 1:0;
|
||||||
|
if (par->vgapass == enable)
|
||||||
|
return;
|
||||||
|
par->vgapass = enable;
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
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);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* change VGA pass_through mode */
|
|
||||||
case _IOW('F', 0xdd, u32): /* 0x46dd */
|
|
||||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
|
||||||
return -EFAULT;
|
|
||||||
pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
|
pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
|
||||||
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
|
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
|
||||||
tmp | PCI_EN_INIT_WR );
|
tmp | PCI_EN_INIT_WR );
|
||||||
fbiinit0 = sst_read (FBIINIT0);
|
fbiinit0 = sst_read (FBIINIT0);
|
||||||
if (val)
|
if (par->vgapass) {
|
||||||
sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH);
|
sst_write(FBIINIT0, fbiinit0 & ~DIS_VGA_PASSTHROUGH);
|
||||||
else
|
printk(KERN_INFO "fb%d: Enabling VGA pass-through\n", info->node );
|
||||||
sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH);
|
} 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);
|
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
/* draw test image */
|
static ssize_t store_vgapass(struct device *device, struct device_attribute *attr,
|
||||||
case _IO('F', 0xde): /* 0x46de */
|
const char *buf, size_t count)
|
||||||
f_dprintk("test color display at %d bpp\n",
|
{
|
||||||
info->var.bits_per_pixel);
|
struct fb_info *info = dev_get_drvdata(device);
|
||||||
sstfb_drawdebugimage(info);
|
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) {
|
||||||
|
/* set/get VGA pass_through mode */
|
||||||
|
case SSTFB_SET_VGAPASS:
|
||||||
|
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||||
|
return -EFAULT;
|
||||||
|
sstfb_setvgapass(info, val);
|
||||||
|
return 0;
|
||||||
|
case SSTFB_GET_VGAPASS:
|
||||||
|
par = info->par;
|
||||||
|
val = par->vgapass;
|
||||||
|
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
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
|
* 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)
|
static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
|
||||||
{
|
{
|
||||||
struct sstfb_par *par = info->par;
|
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) );
|
| (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) );
|
||||||
sst_wait_idle();
|
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 pll_timing gfx_timings;
|
||||||
struct sst_spec *spec;
|
struct sst_spec *spec;
|
||||||
int Fout;
|
int Fout;
|
||||||
|
int gfx_clock;
|
||||||
|
|
||||||
spec = &voodoo_spec[par->type];
|
spec = &voodoo_spec[par->type];
|
||||||
f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 "
|
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 */
|
/* set graphic clock */
|
||||||
par->gfx_clock = spec->default_gfx_clock;
|
gfx_clock = spec->default_gfx_clock;
|
||||||
if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
|
if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
|
||||||
printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk);
|
printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk);
|
||||||
par->gfx_clock = gfxclk *1000;
|
gfx_clock = gfxclk *1000;
|
||||||
} else if (gfxclk) {
|
} else if (gfxclk) {
|
||||||
printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", 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);
|
par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK);
|
||||||
|
|
||||||
/* disable fbiinit remap */
|
/* disable fbiinit remap */
|
||||||
|
@ -1215,10 +1207,11 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
|
||||||
fbiinit0 = FBIINIT0_DEFAULT;
|
fbiinit0 = FBIINIT0_DEFAULT;
|
||||||
fbiinit1 = FBIINIT1_DEFAULT;
|
fbiinit1 = FBIINIT1_DEFAULT;
|
||||||
fbiinit4 = FBIINIT4_DEFAULT;
|
fbiinit4 = FBIINIT4_DEFAULT;
|
||||||
if (vgapass)
|
par->vgapass = vgapass;
|
||||||
fbiinit0 &= ~EN_VGA_PASSTHROUGH;
|
if (par->vgapass)
|
||||||
|
fbiinit0 &= ~DIS_VGA_PASSTHROUGH;
|
||||||
else
|
else
|
||||||
fbiinit0 |= EN_VGA_PASSTHROUGH;
|
fbiinit0 |= DIS_VGA_PASSTHROUGH;
|
||||||
if (slowpci) {
|
if (slowpci) {
|
||||||
fbiinit1 |= SLOW_PCI_WRITES;
|
fbiinit1 |= SLOW_PCI_WRITES;
|
||||||
fbiinit4 |= SLOW_PCI_READS;
|
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... */
|
/* TODO maybe shutdown the dac, vrefresh and so on... */
|
||||||
pci_write_config_dword(dev, PCI_INIT_ENABLE,
|
pci_write_config_dword(dev, PCI_INIT_ENABLE,
|
||||||
PCI_EN_INIT_WR);
|
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);
|
pci_write_config_dword(dev, PCI_VCLK_DISABLE,0);
|
||||||
/* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct
|
/* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct
|
||||||
* from start ? */
|
* from start ? */
|
||||||
|
@ -1278,8 +1271,7 @@ static void __devexit sst_shutdown(struct fb_info *info)
|
||||||
/*
|
/*
|
||||||
* Interface to the world
|
* Interface to the world
|
||||||
*/
|
*/
|
||||||
#ifndef MODULE
|
static int __devinit sstfb_setup(char *options)
|
||||||
static int __init sstfb_setup(char *options)
|
|
||||||
{
|
{
|
||||||
char *this_opt;
|
char *this_opt;
|
||||||
|
|
||||||
|
@ -1312,7 +1304,7 @@ static int __init sstfb_setup(char *options)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct fb_ops sstfb_ops = {
|
static struct fb_ops sstfb_ops = {
|
||||||
.owner = THIS_MODULE,
|
.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 */
|
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);
|
||||||
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;
|
|
||||||
|
|
||||||
if (sstfb_check_var(&info->var, info)) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1442,10 +1429,11 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1) /* set to 0 to see an initial bitmap instead */
|
|
||||||
sstfb_clear_screen(info);
|
sstfb_clear_screen(info);
|
||||||
else
|
|
||||||
sstfb_drawdebugimage(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",
|
printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n",
|
||||||
info->node, fix->id, info->screen_base);
|
info->node, fix->id, info->screen_base);
|
||||||
|
@ -1453,6 +1441,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
fb_dealloc_cmap(&info->cmap);
|
||||||
iounmap(info->screen_base);
|
iounmap(info->screen_base);
|
||||||
fail_fb_remap:
|
fail_fb_remap:
|
||||||
iounmap(par->mmio_vbase);
|
iounmap(par->mmio_vbase);
|
||||||
|
@ -1473,21 +1462,23 @@ static void __devexit sstfb_remove(struct pci_dev *pdev)
|
||||||
info = pci_get_drvdata(pdev);
|
info = pci_get_drvdata(pdev);
|
||||||
par = info->par;
|
par = info->par;
|
||||||
|
|
||||||
|
device_remove_file(info->dev, &device_attrs[0]);
|
||||||
sst_shutdown(info);
|
sst_shutdown(info);
|
||||||
unregister_framebuffer(info);
|
|
||||||
iounmap(info->screen_base);
|
iounmap(info->screen_base);
|
||||||
iounmap(par->mmio_vbase);
|
iounmap(par->mmio_vbase);
|
||||||
release_mem_region(info->fix.smem_start, 0x400000);
|
release_mem_region(info->fix.smem_start, 0x400000);
|
||||||
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
|
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
|
||||||
|
fb_dealloc_cmap(&info->cmap);
|
||||||
|
unregister_framebuffer(info);
|
||||||
framebuffer_release(info);
|
framebuffer_release(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct pci_device_id sstfb_id_tbl[] = {
|
static const struct pci_device_id sstfb_id_tbl[] = {
|
||||||
{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO,
|
{ PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO ),
|
||||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 },
|
.driver_data = ID_VOODOO1, },
|
||||||
{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2,
|
{ PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2),
|
||||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 },
|
.driver_data = ID_VOODOO2, },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1501,142 +1492,23 @@ static struct pci_driver sstfb_driver = {
|
||||||
|
|
||||||
static int __devinit sstfb_init(void)
|
static int __devinit sstfb_init(void)
|
||||||
{
|
{
|
||||||
#ifndef MODULE
|
|
||||||
char *option = NULL;
|
char *option = NULL;
|
||||||
|
|
||||||
if (fb_get_options("sstfb", &option))
|
if (fb_get_options("sstfb", &option))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
sstfb_setup(option);
|
sstfb_setup(option);
|
||||||
#endif
|
|
||||||
return pci_register_driver(&sstfb_driver);
|
return pci_register_driver(&sstfb_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MODULE
|
|
||||||
static void __devexit sstfb_exit(void)
|
static void __devexit sstfb_exit(void)
|
||||||
{
|
{
|
||||||
pci_unregister_driver(&sstfb_driver);
|
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);
|
module_init(sstfb_init);
|
||||||
|
|
||||||
#ifdef MODULE
|
|
||||||
module_exit(sstfb_exit);
|
module_exit(sstfb_exit);
|
||||||
#endif
|
|
||||||
|
|
||||||
MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>");
|
MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>");
|
||||||
MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards");
|
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_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)");
|
||||||
module_param(slowpci, bool, 0);
|
module_param(slowpci, bool, 0);
|
||||||
MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=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 ")");
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
#define BACKPORCH 0x0208
|
#define BACKPORCH 0x0208
|
||||||
#define VIDEODIMENSIONS 0x020c
|
#define VIDEODIMENSIONS 0x020c
|
||||||
#define FBIINIT0 0x0210 /* misc+fifo controls */
|
#define FBIINIT0 0x0210 /* misc+fifo controls */
|
||||||
# define EN_VGA_PASSTHROUGH BIT(0)
|
# define DIS_VGA_PASSTHROUGH BIT(0)
|
||||||
# define FBI_RESET BIT(1)
|
# define FBI_RESET BIT(1)
|
||||||
# define FIFO_RESET BIT(2)
|
# define FIFO_RESET BIT(2)
|
||||||
#define FBIINIT1 0x0214 /* PCI + video controls */
|
#define FBIINIT1 0x0214 /* PCI + video controls */
|
||||||
|
@ -251,7 +251,7 @@
|
||||||
# define DACREG_ICS_CLK1_A 0 /* bit4 */
|
# define DACREG_ICS_CLK1_A 0 /* bit4 */
|
||||||
|
|
||||||
/* sst default init registers */
|
/* sst default init registers */
|
||||||
#define FBIINIT0_DEFAULT EN_VGA_PASSTHROUGH
|
#define FBIINIT0_DEFAULT DIS_VGA_PASSTHROUGH
|
||||||
|
|
||||||
#define FBIINIT1_DEFAULT \
|
#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 */
|
/* used to know witch clock to set */
|
||||||
enum {
|
enum {
|
||||||
VID_CLOCK=0,
|
VID_CLOCK=0,
|
||||||
|
@ -317,7 +322,7 @@ struct pll_timing {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dac_switch {
|
struct dac_switch {
|
||||||
char * name;
|
const char *name;
|
||||||
int (*detect) (struct fb_info *info);
|
int (*detect) (struct fb_info *info);
|
||||||
int (*set_pll) (struct fb_info *info, const struct pll_timing *t, const int clock);
|
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);
|
void (*set_vidmod) (struct fb_info *info, const int bpp);
|
||||||
|
@ -345,7 +350,7 @@ struct sstfb_par {
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
int type;
|
int type;
|
||||||
u8 revision;
|
u8 revision;
|
||||||
int gfx_clock; /* status */
|
u8 vgapass; /* VGA pass through: 1=enabled, 0=disabled */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _SSTFB_H_ */
|
#endif /* _SSTFB_H_ */
|
||||||
|
|
Loading…
Reference in a new issue