diff options
Diffstat (limited to 'drivers/video/amifb.c')
-rw-r--r-- | drivers/video/amifb.c | 286 |
1 files changed, 146 insertions, 140 deletions
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 2bfaf1b86d46..f23cae094f1b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c | |||
@@ -710,7 +710,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite; | |||
710 | * Current Video Mode | 710 | * Current Video Mode |
711 | */ | 711 | */ |
712 | 712 | ||
713 | static struct amifb_par { | 713 | struct amifb_par { |
714 | 714 | ||
715 | /* General Values */ | 715 | /* General Values */ |
716 | 716 | ||
@@ -773,15 +773,6 @@ static struct amifb_par { | |||
773 | /* Additional AGA Hardware Registers */ | 773 | /* Additional AGA Hardware Registers */ |
774 | 774 | ||
775 | u_short fmode; /* vmode */ | 775 | u_short fmode; /* vmode */ |
776 | } currentpar; | ||
777 | |||
778 | |||
779 | static struct fb_info fb_info = { | ||
780 | .fix = { | ||
781 | .id = "Amiga ", | ||
782 | .visual = FB_VISUAL_PSEUDOCOLOR, | ||
783 | .accel = FB_ACCEL_AMIGABLITT | ||
784 | } | ||
785 | }; | 776 | }; |
786 | 777 | ||
787 | 778 | ||
@@ -1130,8 +1121,8 @@ static u_short sprfetchmode[3] = { | |||
1130 | * it up, if it's too big, return -EINVAL. | 1121 | * it up, if it's too big, return -EINVAL. |
1131 | */ | 1122 | */ |
1132 | 1123 | ||
1133 | static int ami_decode_var(struct fb_var_screeninfo *var, | 1124 | static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, |
1134 | struct amifb_par *par) | 1125 | const struct fb_info *info) |
1135 | { | 1126 | { |
1136 | u_short clk_shift, line_shift; | 1127 | u_short clk_shift, line_shift; |
1137 | u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; | 1128 | u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; |
@@ -1449,14 +1440,14 @@ static int ami_decode_var(struct fb_var_screeninfo *var, | |||
1449 | if (amifb_ilbm) { | 1440 | if (amifb_ilbm) { |
1450 | par->next_plane = div8(upx(16 << maxfmode, par->vxres)); | 1441 | par->next_plane = div8(upx(16 << maxfmode, par->vxres)); |
1451 | par->next_line = par->bpp * par->next_plane; | 1442 | par->next_line = par->bpp * par->next_plane; |
1452 | if (par->next_line * par->vyres > fb_info.fix.smem_len) { | 1443 | if (par->next_line * par->vyres > info->fix.smem_len) { |
1453 | DPRINTK("too few video mem\n"); | 1444 | DPRINTK("too few video mem\n"); |
1454 | return -EINVAL; | 1445 | return -EINVAL; |
1455 | } | 1446 | } |
1456 | } else { | 1447 | } else { |
1457 | par->next_line = div8(upx(16 << maxfmode, par->vxres)); | 1448 | par->next_line = div8(upx(16 << maxfmode, par->vxres)); |
1458 | par->next_plane = par->vyres * par->next_line; | 1449 | par->next_plane = par->vyres * par->next_line; |
1459 | if (par->next_plane * par->bpp > fb_info.fix.smem_len) { | 1450 | if (par->next_plane * par->bpp > info->fix.smem_len) { |
1460 | DPRINTK("too few video mem\n"); | 1451 | DPRINTK("too few video mem\n"); |
1461 | return -EINVAL; | 1452 | return -EINVAL; |
1462 | } | 1453 | } |
@@ -1519,8 +1510,8 @@ static int ami_decode_var(struct fb_var_screeninfo *var, | |||
1519 | * other values read out of the hardware. | 1510 | * other values read out of the hardware. |
1520 | */ | 1511 | */ |
1521 | 1512 | ||
1522 | static int ami_encode_var(struct fb_var_screeninfo *var, | 1513 | static void ami_encode_var(struct fb_var_screeninfo *var, |
1523 | struct amifb_par *par) | 1514 | struct amifb_par *par) |
1524 | { | 1515 | { |
1525 | u_short clk_shift, line_shift; | 1516 | u_short clk_shift, line_shift; |
1526 | 1517 | ||
@@ -1596,8 +1587,6 @@ static int ami_encode_var(struct fb_var_screeninfo *var, | |||
1596 | var->sync |= FB_SYNC_EXT; | 1587 | var->sync |= FB_SYNC_EXT; |
1597 | if (par->vmode & FB_VMODE_YWRAP) | 1588 | if (par->vmode & FB_VMODE_YWRAP) |
1598 | var->vmode |= FB_VMODE_YWRAP; | 1589 | var->vmode |= FB_VMODE_YWRAP; |
1599 | |||
1600 | return 0; | ||
1601 | } | 1590 | } |
1602 | 1591 | ||
1603 | 1592 | ||
@@ -1605,9 +1594,9 @@ static int ami_encode_var(struct fb_var_screeninfo *var, | |||
1605 | * Update hardware | 1594 | * Update hardware |
1606 | */ | 1595 | */ |
1607 | 1596 | ||
1608 | static int ami_update_par(void) | 1597 | static void ami_update_par(struct fb_info *info) |
1609 | { | 1598 | { |
1610 | struct amifb_par *par = ¤tpar; | 1599 | struct amifb_par *par = info->par; |
1611 | short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; | 1600 | short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; |
1612 | 1601 | ||
1613 | clk_shift = par->clk_shift; | 1602 | clk_shift = par->clk_shift; |
@@ -1649,11 +1638,11 @@ static int ami_update_par(void) | |||
1649 | par->bpl1mod = par->bpl2mod; | 1638 | par->bpl1mod = par->bpl2mod; |
1650 | 1639 | ||
1651 | if (par->yoffset) { | 1640 | if (par->yoffset) { |
1652 | par->bplpt0 = fb_info.fix.smem_start + | 1641 | par->bplpt0 = info->fix.smem_start + |
1653 | par->next_line * par->yoffset + move; | 1642 | par->next_line * par->yoffset + move; |
1654 | if (par->vmode & FB_VMODE_YWRAP) { | 1643 | if (par->vmode & FB_VMODE_YWRAP) { |
1655 | if (par->yoffset > par->vyres - par->yres) { | 1644 | if (par->yoffset > par->vyres - par->yres) { |
1656 | par->bplpt0wrap = fb_info.fix.smem_start + move; | 1645 | par->bplpt0wrap = info->fix.smem_start + move; |
1657 | if (par->bplcon0 & BPC0_LACE && | 1646 | if (par->bplcon0 & BPC0_LACE && |
1658 | mod2(par->diwstrt_v + par->vyres - | 1647 | mod2(par->diwstrt_v + par->vyres - |
1659 | par->yoffset)) | 1648 | par->yoffset)) |
@@ -1661,12 +1650,10 @@ static int ami_update_par(void) | |||
1661 | } | 1650 | } |
1662 | } | 1651 | } |
1663 | } else | 1652 | } else |
1664 | par->bplpt0 = fb_info.fix.smem_start + move; | 1653 | par->bplpt0 = info->fix.smem_start + move; |
1665 | 1654 | ||
1666 | if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) | 1655 | if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) |
1667 | par->bplpt0 += par->next_line; | 1656 | par->bplpt0 += par->next_line; |
1668 | |||
1669 | return 0; | ||
1670 | } | 1657 | } |
1671 | 1658 | ||
1672 | 1659 | ||
@@ -1677,9 +1664,9 @@ static int ami_update_par(void) | |||
1677 | * in `var'. | 1664 | * in `var'. |
1678 | */ | 1665 | */ |
1679 | 1666 | ||
1680 | static void ami_pan_var(struct fb_var_screeninfo *var) | 1667 | static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) |
1681 | { | 1668 | { |
1682 | struct amifb_par *par = ¤tpar; | 1669 | struct amifb_par *par = info->par; |
1683 | 1670 | ||
1684 | par->xoffset = var->xoffset; | 1671 | par->xoffset = var->xoffset; |
1685 | par->yoffset = var->yoffset; | 1672 | par->yoffset = var->yoffset; |
@@ -1689,15 +1676,13 @@ static void ami_pan_var(struct fb_var_screeninfo *var) | |||
1689 | par->vmode &= ~FB_VMODE_YWRAP; | 1676 | par->vmode &= ~FB_VMODE_YWRAP; |
1690 | 1677 | ||
1691 | do_vmode_pan = 0; | 1678 | do_vmode_pan = 0; |
1692 | ami_update_par(); | 1679 | ami_update_par(info); |
1693 | do_vmode_pan = 1; | 1680 | do_vmode_pan = 1; |
1694 | } | 1681 | } |
1695 | 1682 | ||
1696 | 1683 | ||
1697 | static void ami_update_display(void) | 1684 | static void ami_update_display(const struct amifb_par *par) |
1698 | { | 1685 | { |
1699 | struct amifb_par *par = ¤tpar; | ||
1700 | |||
1701 | custom.bplcon1 = par->bplcon1; | 1686 | custom.bplcon1 = par->bplcon1; |
1702 | custom.bpl1mod = par->bpl1mod; | 1687 | custom.bpl1mod = par->bpl1mod; |
1703 | custom.bpl2mod = par->bpl2mod; | 1688 | custom.bpl2mod = par->bpl2mod; |
@@ -1709,9 +1694,8 @@ static void ami_update_display(void) | |||
1709 | * Change the video mode (called by VBlank interrupt) | 1694 | * Change the video mode (called by VBlank interrupt) |
1710 | */ | 1695 | */ |
1711 | 1696 | ||
1712 | static void ami_init_display(void) | 1697 | static void ami_init_display(const struct amifb_par *par) |
1713 | { | 1698 | { |
1714 | struct amifb_par *par = ¤tpar; | ||
1715 | int i; | 1699 | int i; |
1716 | 1700 | ||
1717 | custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; | 1701 | custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; |
@@ -1764,9 +1748,8 @@ static void ami_init_display(void) | |||
1764 | * (Un)Blank the screen (called by VBlank interrupt) | 1748 | * (Un)Blank the screen (called by VBlank interrupt) |
1765 | */ | 1749 | */ |
1766 | 1750 | ||
1767 | static void ami_do_blank(void) | 1751 | static void ami_do_blank(const struct amifb_par *par) |
1768 | { | 1752 | { |
1769 | struct amifb_par *par = ¤tpar; | ||
1770 | #if defined(CONFIG_FB_AMIGA_AGA) | 1753 | #if defined(CONFIG_FB_AMIGA_AGA) |
1771 | u_short bplcon3 = par->bplcon3; | 1754 | u_short bplcon3 = par->bplcon3; |
1772 | #endif | 1755 | #endif |
@@ -1843,10 +1826,9 @@ static void ami_do_blank(void) | |||
1843 | is_blanked = do_blank > 0 ? do_blank : 0; | 1826 | is_blanked = do_blank > 0 ? do_blank : 0; |
1844 | } | 1827 | } |
1845 | 1828 | ||
1846 | static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) | 1829 | static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, |
1830 | const struct amifb_par *par) | ||
1847 | { | 1831 | { |
1848 | struct amifb_par *par = ¤tpar; | ||
1849 | |||
1850 | fix->crsr_width = fix->crsr_xsize = par->crsr.width; | 1832 | fix->crsr_width = fix->crsr_xsize = par->crsr.width; |
1851 | fix->crsr_height = fix->crsr_ysize = par->crsr.height; | 1833 | fix->crsr_height = fix->crsr_ysize = par->crsr.height; |
1852 | fix->crsr_color1 = 17; | 1834 | fix->crsr_color1 = 17; |
@@ -1854,9 +1836,10 @@ static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) | |||
1854 | return 0; | 1836 | return 0; |
1855 | } | 1837 | } |
1856 | 1838 | ||
1857 | static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) | 1839 | static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, |
1840 | u_char __user *data, | ||
1841 | const struct amifb_par *par) | ||
1858 | { | 1842 | { |
1859 | struct amifb_par *par = ¤tpar; | ||
1860 | register u_short *lspr, *sspr; | 1843 | register u_short *lspr, *sspr; |
1861 | #ifdef __mc68000__ | 1844 | #ifdef __mc68000__ |
1862 | register u_long datawords asm ("d2"); | 1845 | register u_long datawords asm ("d2"); |
@@ -1929,9 +1912,9 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user * | |||
1929 | return 0; | 1912 | return 0; |
1930 | } | 1913 | } |
1931 | 1914 | ||
1932 | static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) | 1915 | static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, |
1916 | u_char __user *data, struct amifb_par *par) | ||
1933 | { | 1917 | { |
1934 | struct amifb_par *par = ¤tpar; | ||
1935 | register u_short *lspr, *sspr; | 1918 | register u_short *lspr, *sspr; |
1936 | #ifdef __mc68000__ | 1919 | #ifdef __mc68000__ |
1937 | register u_long datawords asm ("d2"); | 1920 | register u_long datawords asm ("d2"); |
@@ -2047,20 +2030,18 @@ static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user * | |||
2047 | return 0; | 2030 | return 0; |
2048 | } | 2031 | } |
2049 | 2032 | ||
2050 | static int ami_get_cursorstate(struct fb_cursorstate *state) | 2033 | static int ami_get_cursorstate(struct fb_cursorstate *state, |
2034 | const struct amifb_par *par) | ||
2051 | { | 2035 | { |
2052 | struct amifb_par *par = ¤tpar; | ||
2053 | |||
2054 | state->xoffset = par->crsr.crsr_x; | 2036 | state->xoffset = par->crsr.crsr_x; |
2055 | state->yoffset = par->crsr.crsr_y; | 2037 | state->yoffset = par->crsr.crsr_y; |
2056 | state->mode = cursormode; | 2038 | state->mode = cursormode; |
2057 | return 0; | 2039 | return 0; |
2058 | } | 2040 | } |
2059 | 2041 | ||
2060 | static int ami_set_cursorstate(struct fb_cursorstate *state) | 2042 | static int ami_set_cursorstate(struct fb_cursorstate *state, |
2043 | struct amifb_par *par) | ||
2061 | { | 2044 | { |
2062 | struct amifb_par *par = ¤tpar; | ||
2063 | |||
2064 | par->crsr.crsr_x = state->xoffset; | 2045 | par->crsr.crsr_x = state->xoffset; |
2065 | par->crsr.crsr_y = state->yoffset; | 2046 | par->crsr.crsr_y = state->yoffset; |
2066 | if ((cursormode = state->mode) == FB_CURSOR_OFF) | 2047 | if ((cursormode = state->mode) == FB_CURSOR_OFF) |
@@ -2069,9 +2050,8 @@ static int ami_set_cursorstate(struct fb_cursorstate *state) | |||
2069 | return 0; | 2050 | return 0; |
2070 | } | 2051 | } |
2071 | 2052 | ||
2072 | static void ami_set_sprite(void) | 2053 | static void ami_set_sprite(const struct amifb_par *par) |
2073 | { | 2054 | { |
2074 | struct amifb_par *par = ¤tpar; | ||
2075 | copins *copl, *cops; | 2055 | copins *copl, *cops; |
2076 | u_short hs, vs, ve; | 2056 | u_short hs, vs, ve; |
2077 | u_long pl, ps, pt; | 2057 | u_long pl, ps, pt; |
@@ -2153,10 +2133,8 @@ static void __init ami_init_copper(void) | |||
2153 | custom.copjmp1 = 0; | 2133 | custom.copjmp1 = 0; |
2154 | } | 2134 | } |
2155 | 2135 | ||
2156 | static void ami_reinit_copper(void) | 2136 | static void ami_reinit_copper(const struct amifb_par *par) |
2157 | { | 2137 | { |
2158 | struct amifb_par *par = ¤tpar; | ||
2159 | |||
2160 | copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; | 2138 | copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; |
2161 | copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); | 2139 | copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); |
2162 | } | 2140 | } |
@@ -2168,9 +2146,8 @@ static void ami_reinit_copper(void) | |||
2168 | * We only change the things that are not static | 2146 | * We only change the things that are not static |
2169 | */ | 2147 | */ |
2170 | 2148 | ||
2171 | static void ami_rebuild_copper(void) | 2149 | static void ami_rebuild_copper(const struct amifb_par *par) |
2172 | { | 2150 | { |
2173 | struct amifb_par *par = ¤tpar; | ||
2174 | copins *copl, *cops; | 2151 | copins *copl, *cops; |
2175 | u_short line, h_end1, h_end2; | 2152 | u_short line, h_end1, h_end2; |
2176 | short i; | 2153 | short i; |
@@ -2182,7 +2159,7 @@ static void ami_rebuild_copper(void) | |||
2182 | h_end1 = par->htotal - 32; | 2159 | h_end1 = par->htotal - 32; |
2183 | h_end2 = par->ddfstop + 64; | 2160 | h_end2 = par->ddfstop + 64; |
2184 | 2161 | ||
2185 | ami_set_sprite(); | 2162 | ami_set_sprite(par); |
2186 | 2163 | ||
2187 | copl = copdisplay.rebuild[1]; | 2164 | copl = copdisplay.rebuild[1]; |
2188 | p = par->bplpt0; | 2165 | p = par->bplpt0; |
@@ -2259,9 +2236,9 @@ static void ami_rebuild_copper(void) | |||
2259 | * Build the Copper List | 2236 | * Build the Copper List |
2260 | */ | 2237 | */ |
2261 | 2238 | ||
2262 | static void ami_build_copper(void) | 2239 | static void ami_build_copper(struct fb_info *info) |
2263 | { | 2240 | { |
2264 | struct amifb_par *par = ¤tpar; | 2241 | struct amifb_par *par = info->par; |
2265 | copins *copl, *cops; | 2242 | copins *copl, *cops; |
2266 | u_long p; | 2243 | u_long p; |
2267 | 2244 | ||
@@ -2326,8 +2303,8 @@ static void ami_build_copper(void) | |||
2326 | } | 2303 | } |
2327 | copdisplay.rebuild[1] = copl; | 2304 | copdisplay.rebuild[1] = copl; |
2328 | 2305 | ||
2329 | ami_update_par(); | 2306 | ami_update_par(info); |
2330 | ami_rebuild_copper(); | 2307 | ami_rebuild_copper(info->par); |
2331 | } | 2308 | } |
2332 | 2309 | ||
2333 | 2310 | ||
@@ -2405,7 +2382,8 @@ static int amifb_check_var(struct fb_var_screeninfo *var, | |||
2405 | struct amifb_par par; | 2382 | struct amifb_par par; |
2406 | 2383 | ||
2407 | /* Validate wanted screen parameters */ | 2384 | /* Validate wanted screen parameters */ |
2408 | if ((err = ami_decode_var(var, &par))) | 2385 | err = ami_decode_var(var, &par, info); |
2386 | if (err) | ||
2409 | return err; | 2387 | return err; |
2410 | 2388 | ||
2411 | /* Encode (possibly rounded) screen parameters */ | 2389 | /* Encode (possibly rounded) screen parameters */ |
@@ -2417,15 +2395,18 @@ static int amifb_check_var(struct fb_var_screeninfo *var, | |||
2417 | static int amifb_set_par(struct fb_info *info) | 2395 | static int amifb_set_par(struct fb_info *info) |
2418 | { | 2396 | { |
2419 | struct amifb_par *par = info->par; | 2397 | struct amifb_par *par = info->par; |
2398 | int error; | ||
2420 | 2399 | ||
2421 | do_vmode_pan = 0; | 2400 | do_vmode_pan = 0; |
2422 | do_vmode_full = 0; | 2401 | do_vmode_full = 0; |
2423 | 2402 | ||
2424 | /* Decode wanted screen parameters */ | 2403 | /* Decode wanted screen parameters */ |
2425 | ami_decode_var(&info->var, par); | 2404 | error = ami_decode_var(&info->var, par, info); |
2405 | if (error) | ||
2406 | return error; | ||
2426 | 2407 | ||
2427 | /* Set new videomode */ | 2408 | /* Set new videomode */ |
2428 | ami_build_copper(); | 2409 | ami_build_copper(info); |
2429 | 2410 | ||
2430 | /* Set VBlank trigger */ | 2411 | /* Set VBlank trigger */ |
2431 | do_vmode_full = 1; | 2412 | do_vmode_full = 1; |
@@ -2471,10 +2452,12 @@ static int amifb_set_par(struct fb_info *info) | |||
2471 | static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | 2452 | static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, |
2472 | u_int transp, struct fb_info *info) | 2453 | u_int transp, struct fb_info *info) |
2473 | { | 2454 | { |
2455 | const struct amifb_par *par = info->par; | ||
2456 | |||
2474 | if (IS_AGA) { | 2457 | if (IS_AGA) { |
2475 | if (regno > 255) | 2458 | if (regno > 255) |
2476 | return 1; | 2459 | return 1; |
2477 | } else if (currentpar.bplcon0 & BPC0_SHRES) { | 2460 | } else if (par->bplcon0 & BPC0_SHRES) { |
2478 | if (regno > 3) | 2461 | if (regno > 3) |
2479 | return 1; | 2462 | return 1; |
2480 | } else { | 2463 | } else { |
@@ -2501,7 +2484,7 @@ static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | |||
2501 | if (regno || !is_blanked) { | 2484 | if (regno || !is_blanked) { |
2502 | #if defined(CONFIG_FB_AMIGA_AGA) | 2485 | #if defined(CONFIG_FB_AMIGA_AGA) |
2503 | if (IS_AGA) { | 2486 | if (IS_AGA) { |
2504 | u_short bplcon3 = currentpar.bplcon3; | 2487 | u_short bplcon3 = par->bplcon3; |
2505 | VBlankOff(); | 2488 | VBlankOff(); |
2506 | custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); | 2489 | custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); |
2507 | custom.color[regno & 31] = rgb2hw8_high(red, green, | 2490 | custom.color[regno & 31] = rgb2hw8_high(red, green, |
@@ -2515,7 +2498,7 @@ static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | |||
2515 | } else | 2498 | } else |
2516 | #endif | 2499 | #endif |
2517 | #if defined(CONFIG_FB_AMIGA_ECS) | 2500 | #if defined(CONFIG_FB_AMIGA_ECS) |
2518 | if (currentpar.bplcon0 & BPC0_SHRES) { | 2501 | if (par->bplcon0 & BPC0_SHRES) { |
2519 | u_short color, mask; | 2502 | u_short color, mask; |
2520 | int i; | 2503 | int i; |
2521 | 2504 | ||
@@ -2572,7 +2555,7 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, | |||
2572 | var->yoffset + info->var.yres > info->var.yres_virtual) | 2555 | var->yoffset + info->var.yres > info->var.yres_virtual) |
2573 | return -EINVAL; | 2556 | return -EINVAL; |
2574 | } | 2557 | } |
2575 | ami_pan_var(var); | 2558 | ami_pan_var(var, info); |
2576 | info->var.xoffset = var->xoffset; | 2559 | info->var.xoffset = var->xoffset; |
2577 | info->var.yoffset = var->yoffset; | 2560 | info->var.yoffset = var->yoffset; |
2578 | if (var->vmode & FB_VMODE_YWRAP) | 2561 | if (var->vmode & FB_VMODE_YWRAP) |
@@ -3418,7 +3401,7 @@ static int amifb_ioctl(struct fb_info *info, | |||
3418 | 3401 | ||
3419 | switch (cmd) { | 3402 | switch (cmd) { |
3420 | case FBIOGET_FCURSORINFO: | 3403 | case FBIOGET_FCURSORINFO: |
3421 | i = ami_get_fix_cursorinfo(&crsr.fix); | 3404 | i = ami_get_fix_cursorinfo(&crsr.fix, info->par); |
3422 | if (i) | 3405 | if (i) |
3423 | return i; | 3406 | return i; |
3424 | return copy_to_user(argp, &crsr.fix, | 3407 | return copy_to_user(argp, &crsr.fix, |
@@ -3426,7 +3409,8 @@ static int amifb_ioctl(struct fb_info *info, | |||
3426 | 3409 | ||
3427 | case FBIOGET_VCURSORINFO: | 3410 | case FBIOGET_VCURSORINFO: |
3428 | i = ami_get_var_cursorinfo(&crsr.var, | 3411 | i = ami_get_var_cursorinfo(&crsr.var, |
3429 | ((struct fb_var_cursorinfo __user *)arg)->data); | 3412 | ((struct fb_var_cursorinfo __user *)arg)->data, |
3413 | info->par); | ||
3430 | if (i) | 3414 | if (i) |
3431 | return i; | 3415 | return i; |
3432 | return copy_to_user(argp, &crsr.var, | 3416 | return copy_to_user(argp, &crsr.var, |
@@ -3436,10 +3420,11 @@ static int amifb_ioctl(struct fb_info *info, | |||
3436 | if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) | 3420 | if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) |
3437 | return -EFAULT; | 3421 | return -EFAULT; |
3438 | return ami_set_var_cursorinfo(&crsr.var, | 3422 | return ami_set_var_cursorinfo(&crsr.var, |
3439 | ((struct fb_var_cursorinfo __user *)arg)->data); | 3423 | ((struct fb_var_cursorinfo __user *)arg)->data, |
3424 | info->par); | ||
3440 | 3425 | ||
3441 | case FBIOGET_CURSORSTATE: | 3426 | case FBIOGET_CURSORSTATE: |
3442 | i = ami_get_cursorstate(&crsr.state); | 3427 | i = ami_get_cursorstate(&crsr.state, info->par); |
3443 | if (i) | 3428 | if (i) |
3444 | return i; | 3429 | return i; |
3445 | return copy_to_user(argp, &crsr.state, | 3430 | return copy_to_user(argp, &crsr.state, |
@@ -3448,7 +3433,7 @@ static int amifb_ioctl(struct fb_info *info, | |||
3448 | case FBIOPUT_CURSORSTATE: | 3433 | case FBIOPUT_CURSORSTATE: |
3449 | if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) | 3434 | if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) |
3450 | return -EFAULT; | 3435 | return -EFAULT; |
3451 | return ami_set_cursorstate(&crsr.state); | 3436 | return ami_set_cursorstate(&crsr.state, info->par); |
3452 | } | 3437 | } |
3453 | return -EINVAL; | 3438 | return -EINVAL; |
3454 | } | 3439 | } |
@@ -3479,32 +3464,34 @@ static int flash_cursor(void) | |||
3479 | 3464 | ||
3480 | static irqreturn_t amifb_interrupt(int irq, void *dev_id) | 3465 | static irqreturn_t amifb_interrupt(int irq, void *dev_id) |
3481 | { | 3466 | { |
3467 | struct amifb_par *par = dev_id; | ||
3468 | |||
3482 | if (do_vmode_pan || do_vmode_full) | 3469 | if (do_vmode_pan || do_vmode_full) |
3483 | ami_update_display(); | 3470 | ami_update_display(par); |
3484 | 3471 | ||
3485 | if (do_vmode_full) | 3472 | if (do_vmode_full) |
3486 | ami_init_display(); | 3473 | ami_init_display(par); |
3487 | 3474 | ||
3488 | if (do_vmode_pan) { | 3475 | if (do_vmode_pan) { |
3489 | flash_cursor(); | 3476 | flash_cursor(); |
3490 | ami_rebuild_copper(); | 3477 | ami_rebuild_copper(par); |
3491 | do_cursor = do_vmode_pan = 0; | 3478 | do_cursor = do_vmode_pan = 0; |
3492 | } else if (do_cursor) { | 3479 | } else if (do_cursor) { |
3493 | flash_cursor(); | 3480 | flash_cursor(); |
3494 | ami_set_sprite(); | 3481 | ami_set_sprite(par); |
3495 | do_cursor = 0; | 3482 | do_cursor = 0; |
3496 | } else { | 3483 | } else { |
3497 | if (flash_cursor()) | 3484 | if (flash_cursor()) |
3498 | ami_set_sprite(); | 3485 | ami_set_sprite(par); |
3499 | } | 3486 | } |
3500 | 3487 | ||
3501 | if (do_blank) { | 3488 | if (do_blank) { |
3502 | ami_do_blank(); | 3489 | ami_do_blank(par); |
3503 | do_blank = 0; | 3490 | do_blank = 0; |
3504 | } | 3491 | } |
3505 | 3492 | ||
3506 | if (do_vmode_full) { | 3493 | if (do_vmode_full) { |
3507 | ami_reinit_copper(); | 3494 | ami_reinit_copper(par); |
3508 | do_vmode_full = 0; | 3495 | do_vmode_full = 0; |
3509 | } | 3496 | } |
3510 | return IRQ_HANDLED; | 3497 | return IRQ_HANDLED; |
@@ -3549,23 +3536,13 @@ static inline void chipfree(void) | |||
3549 | } | 3536 | } |
3550 | 3537 | ||
3551 | 3538 | ||
3552 | static void amifb_deinit(struct platform_device *pdev) | ||
3553 | { | ||
3554 | if (fb_info.cmap.len) | ||
3555 | fb_dealloc_cmap(&fb_info.cmap); | ||
3556 | chipfree(); | ||
3557 | if (videomemory) | ||
3558 | iounmap((void *)videomemory); | ||
3559 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | ||
3560 | } | ||
3561 | |||
3562 | |||
3563 | /* | 3539 | /* |
3564 | * Initialisation | 3540 | * Initialisation |
3565 | */ | 3541 | */ |
3566 | 3542 | ||
3567 | static int __init amifb_probe(struct platform_device *pdev) | 3543 | static int __init amifb_probe(struct platform_device *pdev) |
3568 | { | 3544 | { |
3545 | struct fb_info *info; | ||
3569 | int tag, i, err = 0; | 3546 | int tag, i, err = 0; |
3570 | u_long chipptr; | 3547 | u_long chipptr; |
3571 | u_int defmode; | 3548 | u_int defmode; |
@@ -3581,10 +3558,20 @@ static int __init amifb_probe(struct platform_device *pdev) | |||
3581 | #endif | 3558 | #endif |
3582 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | 3559 | custom.dmacon = DMAF_ALL | DMAF_MASTER; |
3583 | 3560 | ||
3561 | info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); | ||
3562 | if (!info) { | ||
3563 | dev_err(&pdev->dev, "framebuffer_alloc failed\n"); | ||
3564 | return -ENOMEM; | ||
3565 | } | ||
3566 | |||
3567 | strcpy(info->fix.id, "Amiga "); | ||
3568 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
3569 | info->fix.accel = FB_ACCEL_AMIGABLITT; | ||
3570 | |||
3584 | switch (amiga_chipset) { | 3571 | switch (amiga_chipset) { |
3585 | #ifdef CONFIG_FB_AMIGA_OCS | 3572 | #ifdef CONFIG_FB_AMIGA_OCS |
3586 | case CS_OCS: | 3573 | case CS_OCS: |
3587 | strcat(fb_info.fix.id, "OCS"); | 3574 | strcat(info->fix.id, "OCS"); |
3588 | default_chipset: | 3575 | default_chipset: |
3589 | chipset = TAG_OCS; | 3576 | chipset = TAG_OCS; |
3590 | maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ | 3577 | maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ |
@@ -3592,13 +3579,13 @@ default_chipset: | |||
3592 | maxdepth[TAG_LORES] = 6; | 3579 | maxdepth[TAG_LORES] = 6; |
3593 | maxfmode = TAG_FMODE_1; | 3580 | maxfmode = TAG_FMODE_1; |
3594 | defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; | 3581 | defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; |
3595 | fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; | 3582 | info->fix.smem_len = VIDEOMEMSIZE_OCS; |
3596 | break; | 3583 | break; |
3597 | #endif /* CONFIG_FB_AMIGA_OCS */ | 3584 | #endif /* CONFIG_FB_AMIGA_OCS */ |
3598 | 3585 | ||
3599 | #ifdef CONFIG_FB_AMIGA_ECS | 3586 | #ifdef CONFIG_FB_AMIGA_ECS |
3600 | case CS_ECS: | 3587 | case CS_ECS: |
3601 | strcat(fb_info.fix.id, "ECS"); | 3588 | strcat(info->fix.id, "ECS"); |
3602 | chipset = TAG_ECS; | 3589 | chipset = TAG_ECS; |
3603 | maxdepth[TAG_SHRES] = 2; | 3590 | maxdepth[TAG_SHRES] = 2; |
3604 | maxdepth[TAG_HIRES] = 4; | 3591 | maxdepth[TAG_HIRES] = 4; |
@@ -3612,15 +3599,15 @@ default_chipset: | |||
3612 | : DEFMODE_NTSC; | 3599 | : DEFMODE_NTSC; |
3613 | if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > | 3600 | if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > |
3614 | VIDEOMEMSIZE_ECS_2M) | 3601 | VIDEOMEMSIZE_ECS_2M) |
3615 | fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; | 3602 | info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; |
3616 | else | 3603 | else |
3617 | fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; | 3604 | info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; |
3618 | break; | 3605 | break; |
3619 | #endif /* CONFIG_FB_AMIGA_ECS */ | 3606 | #endif /* CONFIG_FB_AMIGA_ECS */ |
3620 | 3607 | ||
3621 | #ifdef CONFIG_FB_AMIGA_AGA | 3608 | #ifdef CONFIG_FB_AMIGA_AGA |
3622 | case CS_AGA: | 3609 | case CS_AGA: |
3623 | strcat(fb_info.fix.id, "AGA"); | 3610 | strcat(info->fix.id, "AGA"); |
3624 | chipset = TAG_AGA; | 3611 | chipset = TAG_AGA; |
3625 | maxdepth[TAG_SHRES] = 8; | 3612 | maxdepth[TAG_SHRES] = 8; |
3626 | maxdepth[TAG_HIRES] = 8; | 3613 | maxdepth[TAG_HIRES] = 8; |
@@ -3629,20 +3616,20 @@ default_chipset: | |||
3629 | defmode = DEFMODE_AGA; | 3616 | defmode = DEFMODE_AGA; |
3630 | if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > | 3617 | if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > |
3631 | VIDEOMEMSIZE_AGA_2M) | 3618 | VIDEOMEMSIZE_AGA_2M) |
3632 | fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; | 3619 | info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; |
3633 | else | 3620 | else |
3634 | fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; | 3621 | info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; |
3635 | break; | 3622 | break; |
3636 | #endif /* CONFIG_FB_AMIGA_AGA */ | 3623 | #endif /* CONFIG_FB_AMIGA_AGA */ |
3637 | 3624 | ||
3638 | default: | 3625 | default: |
3639 | #ifdef CONFIG_FB_AMIGA_OCS | 3626 | #ifdef CONFIG_FB_AMIGA_OCS |
3640 | printk("Unknown graphics chipset, defaulting to OCS\n"); | 3627 | printk("Unknown graphics chipset, defaulting to OCS\n"); |
3641 | strcat(fb_info.fix.id, "Unknown"); | 3628 | strcat(info->fix.id, "Unknown"); |
3642 | goto default_chipset; | 3629 | goto default_chipset; |
3643 | #else /* CONFIG_FB_AMIGA_OCS */ | 3630 | #else /* CONFIG_FB_AMIGA_OCS */ |
3644 | err = -ENODEV; | 3631 | err = -ENODEV; |
3645 | goto amifb_error; | 3632 | goto release; |
3646 | #endif /* CONFIG_FB_AMIGA_OCS */ | 3633 | #endif /* CONFIG_FB_AMIGA_OCS */ |
3647 | break; | 3634 | break; |
3648 | } | 3635 | } |
@@ -3672,44 +3659,43 @@ default_chipset: | |||
3672 | } | 3659 | } |
3673 | 3660 | ||
3674 | if (amifb_hfmin) { | 3661 | if (amifb_hfmin) { |
3675 | fb_info.monspecs.hfmin = amifb_hfmin; | 3662 | info->monspecs.hfmin = amifb_hfmin; |
3676 | fb_info.monspecs.hfmax = amifb_hfmax; | 3663 | info->monspecs.hfmax = amifb_hfmax; |
3677 | fb_info.monspecs.vfmin = amifb_vfmin; | 3664 | info->monspecs.vfmin = amifb_vfmin; |
3678 | fb_info.monspecs.vfmax = amifb_vfmax; | 3665 | info->monspecs.vfmax = amifb_vfmax; |
3679 | } else { | 3666 | } else { |
3680 | /* | 3667 | /* |
3681 | * These are for a typical Amiga monitor (e.g. A1960) | 3668 | * These are for a typical Amiga monitor (e.g. A1960) |
3682 | */ | 3669 | */ |
3683 | fb_info.monspecs.hfmin = 15000; | 3670 | info->monspecs.hfmin = 15000; |
3684 | fb_info.monspecs.hfmax = 38000; | 3671 | info->monspecs.hfmax = 38000; |
3685 | fb_info.monspecs.vfmin = 49; | 3672 | info->monspecs.vfmin = 49; |
3686 | fb_info.monspecs.vfmax = 90; | 3673 | info->monspecs.vfmax = 90; |
3687 | } | 3674 | } |
3688 | 3675 | ||
3689 | fb_info.fbops = &amifb_ops; | 3676 | info->fbops = &amifb_ops; |
3690 | fb_info.par = ¤tpar; | 3677 | info->flags = FBINFO_DEFAULT; |
3691 | fb_info.flags = FBINFO_DEFAULT; | 3678 | info->device = &pdev->dev; |
3692 | fb_info.device = &pdev->dev; | ||
3693 | 3679 | ||
3694 | if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, | 3680 | if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, |
3695 | NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { | 3681 | NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { |
3696 | err = -EINVAL; | 3682 | err = -EINVAL; |
3697 | goto amifb_error; | 3683 | goto release; |
3698 | } | 3684 | } |
3699 | 3685 | ||
3700 | fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, | 3686 | fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, |
3701 | &fb_info.modelist); | 3687 | &info->modelist); |
3702 | 3688 | ||
3703 | round_down_bpp = 0; | 3689 | round_down_bpp = 0; |
3704 | chipptr = chipalloc(fb_info.fix.smem_len + SPRITEMEMSIZE + | 3690 | chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + |
3705 | DUMMYSPRITEMEMSIZE + COPINITSIZE + | 3691 | DUMMYSPRITEMEMSIZE + COPINITSIZE + |
3706 | 4 * COPLISTSIZE); | 3692 | 4 * COPLISTSIZE); |
3707 | if (!chipptr) { | 3693 | if (!chipptr) { |
3708 | err = -ENOMEM; | 3694 | err = -ENOMEM; |
3709 | goto amifb_error; | 3695 | goto release; |
3710 | } | 3696 | } |
3711 | 3697 | ||
3712 | assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); | 3698 | assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); |
3713 | assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); | 3699 | assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); |
3714 | assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); | 3700 | assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); |
3715 | assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); | 3701 | assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); |
@@ -3721,14 +3707,15 @@ default_chipset: | |||
3721 | /* | 3707 | /* |
3722 | * access the videomem with writethrough cache | 3708 | * access the videomem with writethrough cache |
3723 | */ | 3709 | */ |
3724 | fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); | 3710 | info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); |
3725 | videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, | 3711 | videomemory = (u_long)ioremap_writethrough(info->fix.smem_start, |
3726 | fb_info.fix.smem_len); | 3712 | info->fix.smem_len); |
3727 | if (!videomemory) { | 3713 | if (!videomemory) { |
3728 | printk("amifb: WARNING! unable to map videomem cached writethrough\n"); | 3714 | dev_warn(&pdev->dev, |
3729 | fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start); | 3715 | "Unable to map videomem cached writethrough\n"); |
3716 | info->screen_base = (char *)ZTWO_VADDR(info->fix.smem_start); | ||
3730 | } else | 3717 | } else |
3731 | fb_info.screen_base = (char *)videomemory; | 3718 | info->screen_base = (char *)videomemory; |
3732 | 3719 | ||
3733 | memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); | 3720 | memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); |
3734 | 3721 | ||
@@ -3743,36 +3730,55 @@ default_chipset: | |||
3743 | custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | | 3730 | custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | |
3744 | DMAF_BLITTER | DMAF_SPRITE; | 3731 | DMAF_BLITTER | DMAF_SPRITE; |
3745 | 3732 | ||
3746 | if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, | 3733 | err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, |
3747 | "fb vertb handler", ¤tpar)) { | 3734 | "fb vertb handler", info->par); |
3748 | err = -EBUSY; | 3735 | if (err) |
3749 | goto amifb_error; | 3736 | goto disable_dma; |
3750 | } | ||
3751 | 3737 | ||
3752 | err = fb_alloc_cmap(&fb_info.cmap, 1 << fb_info.var.bits_per_pixel, 0); | 3738 | err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); |
3753 | if (err) | 3739 | if (err) |
3754 | goto amifb_error; | 3740 | goto free_irq; |
3755 | 3741 | ||
3756 | if (register_framebuffer(&fb_info) < 0) { | 3742 | dev_set_drvdata(&pdev->dev, info); |
3757 | err = -EINVAL; | 3743 | |
3758 | goto amifb_error; | 3744 | err = register_framebuffer(info); |
3759 | } | 3745 | if (err) |
3746 | goto unset_drvdata; | ||
3760 | 3747 | ||
3761 | printk("fb%d: %s frame buffer device, using %dK of video memory\n", | 3748 | printk("fb%d: %s frame buffer device, using %dK of video memory\n", |
3762 | fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10); | 3749 | info->node, info->fix.id, info->fix.smem_len>>10); |
3763 | 3750 | ||
3764 | return 0; | 3751 | return 0; |
3765 | 3752 | ||
3766 | amifb_error: | 3753 | unset_drvdata: |
3767 | amifb_deinit(pdev); | 3754 | dev_set_drvdata(&pdev->dev, NULL); |
3755 | fb_dealloc_cmap(&info->cmap); | ||
3756 | free_irq: | ||
3757 | free_irq(IRQ_AMIGA_COPPER, info->par); | ||
3758 | disable_dma: | ||
3759 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | ||
3760 | if (videomemory) | ||
3761 | iounmap((void *)videomemory); | ||
3762 | chipfree(); | ||
3763 | release: | ||
3764 | framebuffer_release(info); | ||
3768 | return err; | 3765 | return err; |
3769 | } | 3766 | } |
3770 | 3767 | ||
3771 | 3768 | ||
3772 | static int __exit amifb_remove(struct platform_device *pdev) | 3769 | static int __exit amifb_remove(struct platform_device *pdev) |
3773 | { | 3770 | { |
3774 | unregister_framebuffer(&fb_info); | 3771 | struct fb_info *info = dev_get_drvdata(&pdev->dev); |
3775 | amifb_deinit(pdev); | 3772 | |
3773 | unregister_framebuffer(info); | ||
3774 | dev_set_drvdata(&pdev->dev, NULL); | ||
3775 | fb_dealloc_cmap(&info->cmap); | ||
3776 | free_irq(IRQ_AMIGA_COPPER, info->par); | ||
3777 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | ||
3778 | if (videomemory) | ||
3779 | iounmap((void *)videomemory); | ||
3780 | chipfree(); | ||
3781 | framebuffer_release(info); | ||
3776 | amifb_video_off(); | 3782 | amifb_video_off(); |
3777 | return 0; | 3783 | return 0; |
3778 | } | 3784 | } |