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