[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>

authored by

Helge Deller and committed by
Linus Torvalds
0743b868 31619862

+114 -234
+105 -230
drivers/video/sstfb.c
··· 21 * Remove never finished and bogus 24/32bit support 22 * Clean up macro abuse 23 * Minor tidying for format. 24 */ 25 26 /* ··· 70 * 71 * sstfb specific ioctls: 72 * toggle vga (0x46db) : toggle vga_pass_through 73 - * fill fb (0x46dc) : fills fb 74 - * test disp (0x46de) : draws a test image 75 */ 76 77 #undef SST_DEBUG 78 79 - /* 80 - Default video mode . 81 - 0 800x600@60 took from glide 82 - 1 640x480@75 took from glide 83 - 2 1024x768@76 std fb.mode 84 - 3 640x480@60 glide default */ 85 - #define DEFAULT_MODE 3 86 87 /* 88 * Includes ··· 88 #include <linux/init.h> 89 #include <linux/slab.h> 90 #include <asm/io.h> 91 - #include <asm/ioctl.h> 92 #include <asm/uaccess.h> 93 #include <video/sstfb.h> 94 95 96 /* initialized by setup */ 97 98 - static int vgapass; /* enable Vga passthrough cable */ 99 static int mem; /* mem size in MB, 0 = autodetect */ 100 static int clipping = 1; /* use clipping (slower, safer) */ 101 static int gfxclk; /* force FBI freq in Mhz . Dangerous */ 102 static int slowpci; /* slow PCI settings */ 103 104 - static char *mode_option __devinitdata; 105 106 enum { 107 ID_VOODOO1 = 0, ··· 119 { .name = "Voodoo2", .default_gfx_clock = 75000, .max_gfxclk = 85 }, 120 }; 121 122 - static struct fb_var_screeninfo sstfb_default = 123 - #if ( DEFAULT_MODE == 0 ) 124 - { /* 800x600@60, 16 bpp .borowed from glide/sst1/include/sst1init.h */ 125 - 800, 600, 800, 600, 0, 0, 16, 0, 126 - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 127 - 0, 0, -1, -1, 0, 128 - 25000, 86, 41, 23, 1, 127, 4, 129 - 0, FB_VMODE_NONINTERLACED }; 130 - #elif ( DEFAULT_MODE == 1 ) 131 - {/* 640x480@75, 16 bpp .borowed from glide/sst1/include/sst1init.h */ 132 - 640, 480, 640, 480, 0, 0, 16, 0, 133 - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 134 - 0, 0, -1, -1, 0, 135 - 31746, 118, 17, 16, 1, 63, 3, 136 - 0, FB_VMODE_NONINTERLACED }; 137 - #elif ( DEFAULT_MODE == 2 ) 138 - { /* 1024x768@76 took from my /etc/fb.modes */ 139 - 1024, 768, 1024, 768,0, 0, 16,0, 140 - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 141 - 0, 0, -1, -1, 0, 142 - 11764, 208, 8, 36, 16, 120, 3 , 143 - 0, FB_VMODE_NONINTERLACED }; 144 - #elif ( DEFAULT_MODE == 3 ) 145 - { /* 640x480@60 , 16bpp glide default ?*/ 146 - 640, 480, 640, 480, 0, 0, 16, 0, 147 - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 148 - 0, 0, -1, -1, 0, 149 - 39721 , 38, 26 , 25 ,18 , 96 ,2, 150 - 0, FB_VMODE_NONINTERLACED }; 151 - #elif 152 - #error "Invalid DEFAULT_MODE value !" 153 - #endif 154 - 155 156 /* 157 * debug functions 158 */ 159 - 160 - static void sstfb_drawdebugimage(struct fb_info *info); 161 - static int sstfb_dump_regs(struct fb_info *info); 162 - 163 164 #if (SST_DEBUG_REG > 0) 165 static void sst_dbg_print_read_reg(u32 reg, u32 val) { ··· 689 return 0; 690 } 691 692 - static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) 693 { 694 struct sstfb_par *par = info->par; 695 struct pci_dev *sst_dev = par->dev; 696 - u32 fbiinit0, tmp, val; 697 - u_long p; 698 699 switch (cmd) { 700 - 701 - /* dump current FBIINIT values to system log */ 702 - case _IO('F', 0xdb): /* 0x46db */ 703 - return sstfb_dump_regs(info); 704 - 705 - /* fills lfb with #arg pixels */ 706 - case _IOW('F', 0xdc, u32): /* 0x46dc */ 707 if (copy_from_user(&val, (void __user *)arg, sizeof(val))) 708 return -EFAULT; 709 - if (val > info->fix.smem_len) 710 - val = info->fix.smem_len; 711 - for (p = 0 ; p < val; p += 2) 712 - writew(p >> 6, info->screen_base + p); 713 return 0; 714 - 715 - /* change VGA pass_through mode */ 716 - case _IOW('F', 0xdd, u32): /* 0x46dd */ 717 - if (copy_from_user(&val, (void __user *)arg, sizeof(val))) 718 return -EFAULT; 719 - pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp); 720 - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, 721 - tmp | PCI_EN_INIT_WR ); 722 - fbiinit0 = sst_read (FBIINIT0); 723 - if (val) 724 - sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH); 725 - else 726 - sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH); 727 - pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp); 728 - return 0; 729 - 730 - /* draw test image */ 731 - case _IO('F', 0xde): /* 0x46de */ 732 - f_dprintk("test color display at %d bpp\n", 733 - info->var.bits_per_pixel); 734 - sstfb_drawdebugimage(info); 735 return 0; 736 } 737 return -EINVAL; 738 } 739 ··· 793 /* 794 * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only 795 */ 796 static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 797 { 798 struct sstfb_par *par = info->par; ··· 815 | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) ); 816 sst_wait_idle(); 817 } 818 819 820 ··· 1147 struct pll_timing gfx_timings; 1148 struct sst_spec *spec; 1149 int Fout; 1150 1151 spec = &voodoo_spec[par->type]; 1152 f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " ··· 1188 } 1189 1190 /* set graphic clock */ 1191 - par->gfx_clock = spec->default_gfx_clock; 1192 if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { 1193 printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk); 1194 - par->gfx_clock = gfxclk *1000; 1195 } else if (gfxclk) { 1196 printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk); 1197 } 1198 1199 - sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings); 1200 par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); 1201 1202 /* disable fbiinit remap */ ··· 1207 fbiinit0 = FBIINIT0_DEFAULT; 1208 fbiinit1 = FBIINIT1_DEFAULT; 1209 fbiinit4 = FBIINIT4_DEFAULT; 1210 - if (vgapass) 1211 - fbiinit0 &= ~EN_VGA_PASSTHROUGH; 1212 else 1213 - fbiinit0 |= EN_VGA_PASSTHROUGH; 1214 if (slowpci) { 1215 fbiinit1 |= SLOW_PCI_WRITES; 1216 fbiinit4 |= SLOW_PCI_READS; ··· 1260 /* TODO maybe shutdown the dac, vrefresh and so on... */ 1261 pci_write_config_dword(dev, PCI_INIT_ENABLE, 1262 PCI_EN_INIT_WR); 1263 - sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | EN_VGA_PASSTHROUGH); 1264 pci_write_config_dword(dev, PCI_VCLK_DISABLE,0); 1265 /* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct 1266 * from start ? */ ··· 1271 /* 1272 * Interface to the world 1273 */ 1274 - #ifndef MODULE 1275 - static int __init sstfb_setup(char *options) 1276 { 1277 char *this_opt; 1278 ··· 1304 } 1305 return 0; 1306 } 1307 - #endif 1308 1309 static struct fb_ops sstfb_ops = { 1310 .owner = THIS_MODULE, ··· 1408 */ 1409 fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */ 1410 1411 - if ( mode_option && 1412 - fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16)) { 1413 - printk(KERN_ERR "sstfb: can't set supplied video mode. Using default\n"); 1414 - info->var = sstfb_default; 1415 - } else 1416 - info->var = sstfb_default; 1417 1418 if (sstfb_check_var(&info->var, info)) { 1419 - printk(KERN_ERR "sstfb: invalid default video mode.\n"); 1420 goto fail; 1421 } 1422 ··· 1429 goto fail; 1430 } 1431 1432 - if (1) /* set to 0 to see an initial bitmap instead */ 1433 - sstfb_clear_screen(info); 1434 - else 1435 - sstfb_drawdebugimage(info); 1436 1437 printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n", 1438 info->node, fix->id, info->screen_base); ··· 1441 return 0; 1442 1443 fail: 1444 iounmap(info->screen_base); 1445 fail_fb_remap: 1446 iounmap(par->mmio_vbase); ··· 1462 info = pci_get_drvdata(pdev); 1463 par = info->par; 1464 1465 sst_shutdown(info); 1466 - unregister_framebuffer(info); 1467 iounmap(info->screen_base); 1468 iounmap(par->mmio_vbase); 1469 release_mem_region(info->fix.smem_start, 0x400000); 1470 release_mem_region(info->fix.mmio_start, info->fix.mmio_len); 1471 framebuffer_release(info); 1472 } 1473 1474 1475 - static struct pci_device_id sstfb_id_tbl[] = { 1476 - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO, 1477 - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 }, 1478 - { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2, 1479 - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 }, 1480 { 0 }, 1481 }; 1482 ··· 1492 1493 static int __devinit sstfb_init(void) 1494 { 1495 - #ifndef MODULE 1496 char *option = NULL; 1497 1498 if (fb_get_options("sstfb", &option)) 1499 return -ENODEV; 1500 sstfb_setup(option); 1501 - #endif 1502 return pci_register_driver(&sstfb_driver); 1503 } 1504 1505 - #ifdef MODULE 1506 static void __devexit sstfb_exit(void) 1507 { 1508 pci_unregister_driver(&sstfb_driver); 1509 } 1510 - #endif 1511 1512 - 1513 - /* 1514 - * testing and debugging functions 1515 - */ 1516 - 1517 - static int sstfb_dump_regs(struct fb_info *info) 1518 - { 1519 - #ifdef SST_DEBUG 1520 - static struct { u32 reg ; const char *reg_name;} pci_regs[] = { 1521 - { PCI_INIT_ENABLE, "initenable"}, 1522 - { PCI_VCLK_ENABLE, "enable vclk"}, 1523 - { PCI_VCLK_DISABLE, "disable vclk"}, 1524 - }; 1525 - 1526 - static struct { u32 reg ; const char *reg_name;} sst_regs[] = { 1527 - {FBIINIT0,"fbiinit0"}, 1528 - {FBIINIT1,"fbiinit1"}, 1529 - {FBIINIT2,"fbiinit2"}, 1530 - {FBIINIT3,"fbiinit3"}, 1531 - {FBIINIT4,"fbiinit4"}, 1532 - {FBIINIT5,"fbiinit5"}, 1533 - {FBIINIT6,"fbiinit6"}, 1534 - {FBIINIT7,"fbiinit7"}, 1535 - {LFBMODE,"lfbmode"}, 1536 - {FBZMODE,"fbzmode"}, 1537 - }; 1538 - 1539 - const int pci_s = ARRAY_SIZE(pci_regs); 1540 - const int sst_s = ARRAY_SIZE(sst_regs); 1541 - struct sstfb_par *par = info->par; 1542 - struct pci_dev *dev = par->dev; 1543 - u32 pci_res[pci_s]; 1544 - u32 sst_res[sst_s]; 1545 - int i; 1546 - 1547 - for (i=0; i<pci_s; i++) { 1548 - pci_read_config_dword(dev, pci_regs[i].reg, &pci_res[i]); 1549 - } 1550 - for (i=0; i<sst_s; i++) { 1551 - sst_res[i] = sst_read(sst_regs[i].reg); 1552 - } 1553 - 1554 - dprintk("hardware register dump:\n"); 1555 - for (i=0; i<pci_s; i++) { 1556 - dprintk("%s %0#10x\n", pci_regs[i].reg_name, pci_res[i]); 1557 - } 1558 - for (i=0; i<sst_s; i++) { 1559 - dprintk("%s %0#10x\n", sst_regs[i].reg_name, sst_res[i]); 1560 - } 1561 - return 0; 1562 - #else 1563 - return -EINVAL; 1564 - #endif 1565 - } 1566 - 1567 - static void sstfb_fillrect_softw( struct fb_info *info, const struct fb_fillrect *rect) 1568 - { 1569 - u8 __iomem *fbbase_virt = info->screen_base; 1570 - int x, y, w = info->var.bits_per_pixel == 16 ? 2 : 4; 1571 - u32 color = rect->color, height = rect->height; 1572 - u8 __iomem *p; 1573 - 1574 - if (w==2) color |= color<<16; 1575 - for (y=rect->dy; height; y++, height--) { 1576 - p = fbbase_virt + y*info->fix.line_length + rect->dx*w; 1577 - x = rect->width; 1578 - if (w==2) x>>=1; 1579 - while (x) { 1580 - writel(color, p); 1581 - p += 4; 1582 - x--; 1583 - } 1584 - } 1585 - } 1586 - 1587 - static void sstfb_drawrect_XY( struct fb_info *info, int x, int y, 1588 - int w, int h, int color, int hwfunc) 1589 - { 1590 - struct fb_fillrect rect; 1591 - rect.dx = x; 1592 - rect.dy = y; 1593 - rect.height = h; 1594 - rect.width = w; 1595 - rect.color = color; 1596 - rect.rop = ROP_COPY; 1597 - if (hwfunc) 1598 - sstfb_fillrect(info, &rect); 1599 - else 1600 - sstfb_fillrect_softw(info, &rect); 1601 - } 1602 - 1603 - /* print some squares on the fb */ 1604 - static void sstfb_drawdebugimage(struct fb_info *info) 1605 - { 1606 - static int idx; 1607 - 1608 - /* clear screen */ 1609 - sstfb_clear_screen(info); 1610 - 1611 - idx = (idx+1) & 1; 1612 - 1613 - /* white rect */ 1614 - sstfb_drawrect_XY(info, 0, 0, 50, 50, 0xffff, idx); 1615 - 1616 - /* blue rect */ 1617 - sstfb_drawrect_XY(info, 50, 50, 50, 50, 0x001f, idx); 1618 - 1619 - /* green rect */ 1620 - sstfb_drawrect_XY(info, 100, 100, 80, 80, 0x07e0, idx); 1621 - 1622 - /* red rect */ 1623 - sstfb_drawrect_XY(info, 250, 250, 120, 100, 0xf800, idx); 1624 - } 1625 1626 module_init(sstfb_init); 1627 - 1628 - #ifdef MODULE 1629 module_exit(sstfb_exit); 1630 - #endif 1631 1632 MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>"); 1633 MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards"); ··· 1524 MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)"); 1525 module_param(slowpci, bool, 0); 1526 MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)");
··· 21 * Remove never finished and bogus 24/32bit support 22 * Clean up macro abuse 23 * Minor tidying for format. 24 + * 12/2006 Helge Deller <deller@gmx.de> 25 + * add /sys/class/graphics/fbX/vgapass sysfs-interface 26 + * add module option "mode_option" to set initial screen mode 27 + * use fbdev default videomode database 28 + * remove debug functions from ioctl 29 */ 30 31 /* ··· 65 * 66 * sstfb specific ioctls: 67 * toggle vga (0x46db) : toggle vga_pass_through 68 */ 69 70 #undef SST_DEBUG 71 72 73 /* 74 * Includes ··· 92 #include <linux/init.h> 93 #include <linux/slab.h> 94 #include <asm/io.h> 95 #include <asm/uaccess.h> 96 #include <video/sstfb.h> 97 98 99 /* initialized by setup */ 100 101 + static int vgapass; /* enable VGA passthrough cable */ 102 static int mem; /* mem size in MB, 0 = autodetect */ 103 static int clipping = 1; /* use clipping (slower, safer) */ 104 static int gfxclk; /* force FBI freq in Mhz . Dangerous */ 105 static int slowpci; /* slow PCI settings */ 106 107 + /* 108 + Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60 109 + */ 110 + #define DEFAULT_VIDEO_MODE "640x480@60" 111 + 112 + static char *mode_option __devinitdata = DEFAULT_VIDEO_MODE; 113 114 enum { 115 ID_VOODOO1 = 0, ··· 119 { .name = "Voodoo2", .default_gfx_clock = 75000, .max_gfxclk = 85 }, 120 }; 121 122 123 /* 124 * debug functions 125 */ 126 127 #if (SST_DEBUG_REG > 0) 128 static void sst_dbg_print_read_reg(u32 reg, u32 val) { ··· 726 return 0; 727 } 728 729 + static void sstfb_setvgapass( struct fb_info *info, int enable ) 730 { 731 struct sstfb_par *par = info->par; 732 struct pci_dev *sst_dev = par->dev; 733 + u32 fbiinit0, tmp; 734 + 735 + enable = enable ? 1:0; 736 + if (par->vgapass == enable) 737 + return; 738 + par->vgapass = enable; 739 + 740 + pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp); 741 + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, 742 + tmp | PCI_EN_INIT_WR ); 743 + fbiinit0 = sst_read (FBIINIT0); 744 + if (par->vgapass) { 745 + sst_write(FBIINIT0, fbiinit0 & ~DIS_VGA_PASSTHROUGH); 746 + printk(KERN_INFO "fb%d: Enabling VGA pass-through\n", info->node ); 747 + } else { 748 + sst_write(FBIINIT0, fbiinit0 | DIS_VGA_PASSTHROUGH); 749 + printk(KERN_INFO "fb%d: Disabling VGA pass-through\n", info->node ); 750 + } 751 + pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp); 752 + } 753 + 754 + static ssize_t store_vgapass(struct device *device, struct device_attribute *attr, 755 + const char *buf, size_t count) 756 + { 757 + struct fb_info *info = dev_get_drvdata(device); 758 + char ** last = NULL; 759 + int val; 760 + 761 + val = simple_strtoul(buf, last, 0); 762 + sstfb_setvgapass(info, val); 763 + 764 + return count; 765 + } 766 + 767 + static ssize_t show_vgapass(struct device *device, struct device_attribute *attr, 768 + char *buf) 769 + { 770 + struct fb_info *info = dev_get_drvdata(device); 771 + struct sstfb_par *par = info->par; 772 + return snprintf(buf, PAGE_SIZE, "%d\n", par->vgapass); 773 + } 774 + 775 + static struct device_attribute device_attrs[] = { 776 + __ATTR(vgapass, S_IRUGO|S_IWUSR, show_vgapass, store_vgapass) 777 + }; 778 + 779 + static int sstfb_ioctl(struct fb_info *info, unsigned int cmd, 780 + unsigned long arg) 781 + { 782 + struct sstfb_par *par; 783 + u32 val; 784 785 switch (cmd) { 786 + /* set/get VGA pass_through mode */ 787 + case SSTFB_SET_VGAPASS: 788 if (copy_from_user(&val, (void __user *)arg, sizeof(val))) 789 return -EFAULT; 790 + sstfb_setvgapass(info, val); 791 return 0; 792 + case SSTFB_GET_VGAPASS: 793 + par = info->par; 794 + val = par->vgapass; 795 + if (copy_to_user((void __user *)arg, &val, sizeof(val))) 796 return -EFAULT; 797 return 0; 798 } 799 + 800 return -EINVAL; 801 } 802 ··· 804 /* 805 * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only 806 */ 807 + #if 0 808 static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 809 { 810 struct sstfb_par *par = info->par; ··· 825 | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) ); 826 sst_wait_idle(); 827 } 828 + #endif 829 830 831 ··· 1156 struct pll_timing gfx_timings; 1157 struct sst_spec *spec; 1158 int Fout; 1159 + int gfx_clock; 1160 1161 spec = &voodoo_spec[par->type]; 1162 f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " ··· 1196 } 1197 1198 /* set graphic clock */ 1199 + gfx_clock = spec->default_gfx_clock; 1200 if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { 1201 printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk); 1202 + gfx_clock = gfxclk *1000; 1203 } else if (gfxclk) { 1204 printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk); 1205 } 1206 1207 + sst_calc_pll(gfx_clock, &Fout, &gfx_timings); 1208 par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); 1209 1210 /* disable fbiinit remap */ ··· 1215 fbiinit0 = FBIINIT0_DEFAULT; 1216 fbiinit1 = FBIINIT1_DEFAULT; 1217 fbiinit4 = FBIINIT4_DEFAULT; 1218 + par->vgapass = vgapass; 1219 + if (par->vgapass) 1220 + fbiinit0 &= ~DIS_VGA_PASSTHROUGH; 1221 else 1222 + fbiinit0 |= DIS_VGA_PASSTHROUGH; 1223 if (slowpci) { 1224 fbiinit1 |= SLOW_PCI_WRITES; 1225 fbiinit4 |= SLOW_PCI_READS; ··· 1267 /* TODO maybe shutdown the dac, vrefresh and so on... */ 1268 pci_write_config_dword(dev, PCI_INIT_ENABLE, 1269 PCI_EN_INIT_WR); 1270 + sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | DIS_VGA_PASSTHROUGH); 1271 pci_write_config_dword(dev, PCI_VCLK_DISABLE,0); 1272 /* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct 1273 * from start ? */ ··· 1278 /* 1279 * Interface to the world 1280 */ 1281 + static int __devinit sstfb_setup(char *options) 1282 { 1283 char *this_opt; 1284 ··· 1312 } 1313 return 0; 1314 } 1315 + 1316 1317 static struct fb_ops sstfb_ops = { 1318 .owner = THIS_MODULE, ··· 1416 */ 1417 fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */ 1418 1419 + fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); 1420 1421 if (sstfb_check_var(&info->var, info)) { 1422 + printk(KERN_ERR "sstfb: invalid video mode.\n"); 1423 goto fail; 1424 } 1425 ··· 1442 goto fail; 1443 } 1444 1445 + sstfb_clear_screen(info); 1446 + 1447 + if (device_create_file(info->dev, &device_attrs[0])) 1448 + printk(KERN_WARNING "sstfb: can't create sysfs entry.\n"); 1449 + 1450 1451 printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n", 1452 info->node, fix->id, info->screen_base); ··· 1453 return 0; 1454 1455 fail: 1456 + fb_dealloc_cmap(&info->cmap); 1457 iounmap(info->screen_base); 1458 fail_fb_remap: 1459 iounmap(par->mmio_vbase); ··· 1473 info = pci_get_drvdata(pdev); 1474 par = info->par; 1475 1476 + device_remove_file(info->dev, &device_attrs[0]); 1477 sst_shutdown(info); 1478 iounmap(info->screen_base); 1479 iounmap(par->mmio_vbase); 1480 release_mem_region(info->fix.smem_start, 0x400000); 1481 release_mem_region(info->fix.mmio_start, info->fix.mmio_len); 1482 + fb_dealloc_cmap(&info->cmap); 1483 + unregister_framebuffer(info); 1484 framebuffer_release(info); 1485 } 1486 1487 1488 + static const struct pci_device_id sstfb_id_tbl[] = { 1489 + { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO ), 1490 + .driver_data = ID_VOODOO1, }, 1491 + { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2), 1492 + .driver_data = ID_VOODOO2, }, 1493 { 0 }, 1494 }; 1495 ··· 1501 1502 static int __devinit sstfb_init(void) 1503 { 1504 char *option = NULL; 1505 1506 if (fb_get_options("sstfb", &option)) 1507 return -ENODEV; 1508 sstfb_setup(option); 1509 + 1510 return pci_register_driver(&sstfb_driver); 1511 } 1512 1513 static void __devexit sstfb_exit(void) 1514 { 1515 pci_unregister_driver(&sstfb_driver); 1516 } 1517 1518 1519 module_init(sstfb_init); 1520 module_exit(sstfb_exit); 1521 1522 MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>"); 1523 MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards"); ··· 1652 MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)"); 1653 module_param(slowpci, bool, 0); 1654 MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)"); 1655 + module_param(mode_option, charp, 0); 1656 + MODULE_PARM_DESC(mode_option, "Initial video mode (default=" DEFAULT_VIDEO_MODE ")"); 1657 +
+9 -4
include/video/sstfb.h
··· 119 #define BACKPORCH 0x0208 120 #define VIDEODIMENSIONS 0x020c 121 #define FBIINIT0 0x0210 /* misc+fifo controls */ 122 - # define EN_VGA_PASSTHROUGH BIT(0) 123 # define FBI_RESET BIT(1) 124 # define FIFO_RESET BIT(2) 125 #define FBIINIT1 0x0214 /* PCI + video controls */ ··· 251 # define DACREG_ICS_CLK1_A 0 /* bit4 */ 252 253 /* sst default init registers */ 254 - #define FBIINIT0_DEFAULT EN_VGA_PASSTHROUGH 255 256 #define FBIINIT1_DEFAULT \ 257 ( \ ··· 296 * 297 */ 298 299 /* used to know witch clock to set */ 300 enum { 301 VID_CLOCK=0, ··· 322 }; 323 324 struct dac_switch { 325 - char * name; 326 int (*detect) (struct fb_info *info); 327 int (*set_pll) (struct fb_info *info, const struct pll_timing *t, const int clock); 328 void (*set_vidmod) (struct fb_info *info, const int bpp); ··· 350 struct pci_dev *dev; 351 int type; 352 u8 revision; 353 - int gfx_clock; /* status */ 354 }; 355 356 #endif /* _SSTFB_H_ */
··· 119 #define BACKPORCH 0x0208 120 #define VIDEODIMENSIONS 0x020c 121 #define FBIINIT0 0x0210 /* misc+fifo controls */ 122 + # define DIS_VGA_PASSTHROUGH BIT(0) 123 # define FBI_RESET BIT(1) 124 # define FIFO_RESET BIT(2) 125 #define FBIINIT1 0x0214 /* PCI + video controls */ ··· 251 # define DACREG_ICS_CLK1_A 0 /* bit4 */ 252 253 /* sst default init registers */ 254 + #define FBIINIT0_DEFAULT DIS_VGA_PASSTHROUGH 255 256 #define FBIINIT1_DEFAULT \ 257 ( \ ··· 296 * 297 */ 298 299 + /* ioctl to enable/disable VGA passthrough */ 300 + #define SSTFB_SET_VGAPASS _IOW('F', 0xdd, __u32) 301 + #define SSTFB_GET_VGAPASS _IOR('F', 0xdd, __u32) 302 + 303 + 304 /* used to know witch clock to set */ 305 enum { 306 VID_CLOCK=0, ··· 317 }; 318 319 struct dac_switch { 320 + const char *name; 321 int (*detect) (struct fb_info *info); 322 int (*set_pll) (struct fb_info *info, const struct pll_timing *t, const int clock); 323 void (*set_vidmod) (struct fb_info *info, const int bpp); ··· 345 struct pci_dev *dev; 346 int type; 347 u8 revision; 348 + u8 vgapass; /* VGA pass through: 1=enabled, 0=disabled */ 349 }; 350 351 #endif /* _SSTFB_H_ */