diff options
author | Ben Dooks <ben-linux@fluff.org> | 2008-07-24 00:31:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 13:47:40 -0400 |
commit | 9b599fb2fc23386dfd2965bf7d10b2b0f628b208 (patch) | |
tree | aad37295d1c6e5246bd31d785bef92755a9b2d89 /drivers/video/sm501fb.c | |
parent | 206c5d69d0540024faffd423fc703f1e457332d7 (diff) |
sm501: restructure init to allow only 1 fb on an SM501
Add the ability to register only one of the two possible main framebuffer
devices on the SM501 by passing platform data for only the framebuffer
that you are interested in having.
As a side note, we update the init sequence to commonise the code that is
executed twice, and fix a pair of missing frees that we didn't do on
framebuffer exit, such as freeing the fb's cmap.
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/sm501fb.c')
-rw-r--r-- | drivers/video/sm501fb.c | 264 |
1 files changed, 149 insertions, 115 deletions
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 122a0f8495c8..b473cf665d83 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c | |||
@@ -143,6 +143,8 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | |||
143 | unsigned int why, size_t size) | 143 | unsigned int why, size_t size) |
144 | { | 144 | { |
145 | unsigned int ptr = 0; | 145 | unsigned int ptr = 0; |
146 | unsigned int end; | ||
147 | struct fb_info *fbi; | ||
146 | 148 | ||
147 | switch (why) { | 149 | switch (why) { |
148 | case SM501_MEMF_CURSOR: | 150 | case SM501_MEMF_CURSOR: |
@@ -152,7 +154,9 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | |||
152 | 154 | ||
153 | case SM501_MEMF_PANEL: | 155 | case SM501_MEMF_PANEL: |
154 | ptr = inf->fbmem_len - size; | 156 | ptr = inf->fbmem_len - size; |
155 | if (ptr < inf->fb[0]->fix.smem_len) | 157 | fbi = inf->fb[0]; |
158 | |||
159 | if (fbi && ptr < fbi->fix.smem_len) | ||
156 | return -ENOMEM; | 160 | return -ENOMEM; |
157 | 161 | ||
158 | break; | 162 | break; |
@@ -162,11 +166,18 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | |||
162 | break; | 166 | break; |
163 | 167 | ||
164 | case SM501_MEMF_ACCEL: | 168 | case SM501_MEMF_ACCEL: |
165 | ptr = inf->fb[0]->fix.smem_len; | 169 | fbi = inf->fb[0]; |
170 | ptr = fbi ? fbi->fix.smem_len : 0; | ||
171 | |||
172 | fbi = inf->fb[1]; | ||
173 | if (fbi) | ||
174 | end = (fbi->fix.smem_start - inf->fbmem_res->start); | ||
175 | else | ||
176 | end = inf->fbmem_len; | ||
166 | 177 | ||
167 | if ((ptr + size) > | 178 | if ((ptr + size) > end) |
168 | (inf->fb[1]->fix.smem_start - inf->fbmem_res->start)) | ||
169 | return -ENOMEM; | 179 | return -ENOMEM; |
180 | |||
170 | break; | 181 | break; |
171 | 182 | ||
172 | default: | 183 | default: |
@@ -1228,39 +1239,6 @@ static struct fb_ops sm501fb_ops_pnl = { | |||
1228 | .fb_imageblit = cfb_imageblit, | 1239 | .fb_imageblit = cfb_imageblit, |
1229 | }; | 1240 | }; |
1230 | 1241 | ||
1231 | /* sm501fb_info_alloc | ||
1232 | * | ||
1233 | * creates and initialises an sm501fb_info structure | ||
1234 | */ | ||
1235 | |||
1236 | static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt, | ||
1237 | struct fb_info *fbinfo_pnl) | ||
1238 | { | ||
1239 | struct sm501fb_info *info; | ||
1240 | struct sm501fb_par *par; | ||
1241 | |||
1242 | info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); | ||
1243 | if (info) { | ||
1244 | /* set the references back */ | ||
1245 | |||
1246 | par = fbinfo_crt->par; | ||
1247 | par->info = info; | ||
1248 | par->head = HEAD_CRT; | ||
1249 | fbinfo_crt->pseudo_palette = &par->pseudo_palette; | ||
1250 | |||
1251 | par = fbinfo_pnl->par; | ||
1252 | par->info = info; | ||
1253 | par->head = HEAD_PANEL; | ||
1254 | fbinfo_pnl->pseudo_palette = &par->pseudo_palette; | ||
1255 | |||
1256 | /* store the two fbs into our info */ | ||
1257 | info->fb[HEAD_CRT] = fbinfo_crt; | ||
1258 | info->fb[HEAD_PANEL] = fbinfo_pnl; | ||
1259 | } | ||
1260 | |||
1261 | return info; | ||
1262 | } | ||
1263 | |||
1264 | /* sm501_init_cursor | 1242 | /* sm501_init_cursor |
1265 | * | 1243 | * |
1266 | * initialise hw cursor parameters | 1244 | * initialise hw cursor parameters |
@@ -1268,10 +1246,16 @@ static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt, | |||
1268 | 1246 | ||
1269 | static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) | 1247 | static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) |
1270 | { | 1248 | { |
1271 | struct sm501fb_par *par = fbi->par; | 1249 | struct sm501fb_par *par; |
1272 | struct sm501fb_info *info = par->info; | 1250 | struct sm501fb_info *info; |
1273 | int ret; | 1251 | int ret; |
1274 | 1252 | ||
1253 | if (fbi == NULL) | ||
1254 | return 0; | ||
1255 | |||
1256 | par = fbi->par; | ||
1257 | info = par->info; | ||
1258 | |||
1275 | par->cursor_regs = info->regs + reg_base; | 1259 | par->cursor_regs = info->regs + reg_base; |
1276 | 1260 | ||
1277 | ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); | 1261 | ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); |
@@ -1299,13 +1283,10 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1299 | struct platform_device *pdev) | 1283 | struct platform_device *pdev) |
1300 | { | 1284 | { |
1301 | struct resource *res; | 1285 | struct resource *res; |
1302 | struct device *dev; | 1286 | struct device *dev = &pdev->dev; |
1303 | int k; | 1287 | int k; |
1304 | int ret; | 1288 | int ret; |
1305 | 1289 | ||
1306 | info->dev = dev = &pdev->dev; | ||
1307 | platform_set_drvdata(pdev, info); | ||
1308 | |||
1309 | info->irq = ret = platform_get_irq(pdev, 0); | 1290 | info->irq = ret = platform_get_irq(pdev, 0); |
1310 | if (ret < 0) { | 1291 | if (ret < 0) { |
1311 | /* we currently do not use the IRQ */ | 1292 | /* we currently do not use the IRQ */ |
@@ -1408,11 +1389,6 @@ static void sm501fb_stop(struct sm501fb_info *info) | |||
1408 | kfree(info->regs_res); | 1389 | kfree(info->regs_res); |
1409 | } | 1390 | } |
1410 | 1391 | ||
1411 | static void sm501fb_info_release(struct sm501fb_info *info) | ||
1412 | { | ||
1413 | kfree(info); | ||
1414 | } | ||
1415 | |||
1416 | static int sm501fb_init_fb(struct fb_info *fb, | 1392 | static int sm501fb_init_fb(struct fb_info *fb, |
1417 | enum sm501_controller head, | 1393 | enum sm501_controller head, |
1418 | const char *fbname) | 1394 | const char *fbname) |
@@ -1557,36 +1533,93 @@ static struct sm501_platdata_fb sm501fb_def_pdata = { | |||
1557 | static char driver_name_crt[] = "sm501fb-crt"; | 1533 | static char driver_name_crt[] = "sm501fb-crt"; |
1558 | static char driver_name_pnl[] = "sm501fb-panel"; | 1534 | static char driver_name_pnl[] = "sm501fb-panel"; |
1559 | 1535 | ||
1560 | static int __init sm501fb_probe(struct platform_device *pdev) | 1536 | static int __devinit sm501fb_probe_one(struct sm501fb_info *info, |
1537 | enum sm501_controller head) | ||
1561 | { | 1538 | { |
1562 | struct sm501fb_info *info; | 1539 | unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel"; |
1563 | struct device *dev = &pdev->dev; | 1540 | struct sm501_platdata_fbsub *pd; |
1564 | struct fb_info *fbinfo_crt; | 1541 | struct sm501fb_par *par; |
1565 | struct fb_info *fbinfo_pnl; | 1542 | struct fb_info *fbi; |
1566 | int ret; | ||
1567 | 1543 | ||
1568 | /* allocate our framebuffers */ | 1544 | pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl; |
1569 | 1545 | ||
1570 | fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev); | 1546 | /* Do not initialise if we've not been given any platform data */ |
1571 | if (fbinfo_crt == NULL) { | 1547 | if (pd == NULL) { |
1572 | dev_err(dev, "cannot allocate crt framebuffer\n"); | 1548 | dev_info(info->dev, "no data for fb %s (disabled)\n", name); |
1549 | return 0; | ||
1550 | } | ||
1551 | |||
1552 | fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev); | ||
1553 | if (fbi == NULL) { | ||
1554 | dev_err(info->dev, "cannot allocate %s framebuffer\n", name); | ||
1573 | return -ENOMEM; | 1555 | return -ENOMEM; |
1574 | } | 1556 | } |
1575 | 1557 | ||
1576 | fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev); | 1558 | par = fbi->par; |
1577 | if (fbinfo_pnl == NULL) { | 1559 | par->info = info; |
1578 | dev_err(dev, "cannot allocate panel framebuffer\n"); | 1560 | par->head = head; |
1579 | ret = -ENOMEM; | 1561 | fbi->pseudo_palette = &par->pseudo_palette; |
1580 | goto fbinfo_crt_alloc_fail; | 1562 | |
1563 | info->fb[head] = fbi; | ||
1564 | |||
1565 | return 0; | ||
1566 | } | ||
1567 | |||
1568 | /* Free up anything allocated by sm501fb_init_fb */ | ||
1569 | |||
1570 | static void sm501_free_init_fb(struct sm501fb_info *info, | ||
1571 | enum sm501_controller head) | ||
1572 | { | ||
1573 | struct fb_info *fbi = info->fb[head]; | ||
1574 | |||
1575 | fb_dealloc_cmap(&fbi->cmap); | ||
1576 | } | ||
1577 | |||
1578 | static int __devinit sm501fb_start_one(struct sm501fb_info *info, | ||
1579 | enum sm501_controller head, | ||
1580 | const char *drvname) | ||
1581 | { | ||
1582 | struct fb_info *fbi = info->fb[head]; | ||
1583 | int ret; | ||
1584 | |||
1585 | if (!fbi) | ||
1586 | return 0; | ||
1587 | |||
1588 | ret = sm501fb_init_fb(info->fb[head], head, drvname); | ||
1589 | if (ret) { | ||
1590 | dev_err(info->dev, "cannot initialise fb %s\n", drvname); | ||
1591 | return ret; | ||
1592 | } | ||
1593 | |||
1594 | ret = register_framebuffer(info->fb[head]); | ||
1595 | if (ret) { | ||
1596 | dev_err(info->dev, "failed to register fb %s\n", drvname); | ||
1597 | sm501_free_init_fb(info, head); | ||
1598 | return ret; | ||
1581 | } | 1599 | } |
1582 | 1600 | ||
1583 | info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl); | 1601 | dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id); |
1584 | if (info == NULL) { | 1602 | |
1585 | dev_err(dev, "cannot allocate par\n"); | 1603 | return 0; |
1586 | ret = -ENOMEM; | 1604 | } |
1587 | goto sm501fb_alloc_fail; | 1605 | |
1606 | static int __devinit sm501fb_probe(struct platform_device *pdev) | ||
1607 | { | ||
1608 | struct sm501fb_info *info; | ||
1609 | struct device *dev = &pdev->dev; | ||
1610 | int ret; | ||
1611 | |||
1612 | /* allocate our framebuffers */ | ||
1613 | |||
1614 | info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); | ||
1615 | if (!info) { | ||
1616 | dev_err(dev, "failed to allocate state\n"); | ||
1617 | return -ENOMEM; | ||
1588 | } | 1618 | } |
1589 | 1619 | ||
1620 | info->dev = dev = &pdev->dev; | ||
1621 | platform_set_drvdata(pdev, info); | ||
1622 | |||
1590 | if (dev->parent->platform_data) { | 1623 | if (dev->parent->platform_data) { |
1591 | struct sm501_platdata *pd = dev->parent->platform_data; | 1624 | struct sm501_platdata *pd = dev->parent->platform_data; |
1592 | info->pdata = pd->fb; | 1625 | info->pdata = pd->fb; |
@@ -1597,90 +1630,88 @@ static int __init sm501fb_probe(struct platform_device *pdev) | |||
1597 | info->pdata = &sm501fb_def_pdata; | 1630 | info->pdata = &sm501fb_def_pdata; |
1598 | } | 1631 | } |
1599 | 1632 | ||
1600 | /* start the framebuffers */ | 1633 | /* probe for the presence of each panel */ |
1601 | 1634 | ||
1602 | ret = sm501fb_start(info, pdev); | 1635 | ret = sm501fb_probe_one(info, HEAD_CRT); |
1603 | if (ret) { | 1636 | if (ret < 0) { |
1604 | dev_err(dev, "cannot initialise SM501\n"); | 1637 | dev_err(dev, "failed to probe CRT\n"); |
1605 | goto sm501fb_start_fail; | 1638 | goto err_alloc; |
1606 | } | 1639 | } |
1607 | 1640 | ||
1608 | /* CRT framebuffer setup */ | 1641 | ret = sm501fb_probe_one(info, HEAD_PANEL); |
1642 | if (ret < 0) { | ||
1643 | dev_err(dev, "failed to probe PANEL\n"); | ||
1644 | goto err_probed_crt; | ||
1645 | } | ||
1609 | 1646 | ||
1610 | ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt); | 1647 | if (info->fb[HEAD_PANEL] == NULL && |
1611 | if (ret) { | 1648 | info->fb[HEAD_CRT] == NULL) { |
1612 | dev_err(dev, "cannot initialise CRT fb\n"); | 1649 | dev_err(dev, "no framebuffers found\n"); |
1613 | goto sm501fb_start_fail; | 1650 | goto err_alloc; |
1614 | } | 1651 | } |
1615 | 1652 | ||
1616 | /* Panel framebuffer setup */ | 1653 | /* get the resources for both of the framebuffers */ |
1617 | 1654 | ||
1618 | ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl); | 1655 | ret = sm501fb_start(info, pdev); |
1619 | if (ret) { | 1656 | if (ret) { |
1620 | dev_err(dev, "cannot initialise Panel fb\n"); | 1657 | dev_err(dev, "cannot initialise SM501\n"); |
1621 | goto sm501fb_start_fail; | 1658 | goto err_probed_panel; |
1622 | } | 1659 | } |
1623 | 1660 | ||
1624 | /* register framebuffers */ | 1661 | ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt); |
1625 | 1662 | if (ret) { | |
1626 | ret = register_framebuffer(fbinfo_crt); | 1663 | dev_err(dev, "failed to start CRT\n"); |
1627 | if (ret < 0) { | 1664 | goto err_started; |
1628 | dev_err(dev, "failed to register CRT fb (%d)\n", ret); | ||
1629 | goto register_crt_fail; | ||
1630 | } | 1665 | } |
1631 | 1666 | ||
1632 | ret = register_framebuffer(fbinfo_pnl); | 1667 | ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl); |
1633 | if (ret < 0) { | 1668 | if (ret) { |
1634 | dev_err(dev, "failed to register panel fb (%d)\n", ret); | 1669 | dev_err(dev, "failed to start Panel\n"); |
1635 | goto register_pnl_fail; | 1670 | goto err_started_crt; |
1636 | } | 1671 | } |
1637 | 1672 | ||
1638 | dev_info(dev, "fb%d: %s frame buffer device\n", | ||
1639 | fbinfo_crt->node, fbinfo_crt->fix.id); | ||
1640 | |||
1641 | dev_info(dev, "fb%d: %s frame buffer device\n", | ||
1642 | fbinfo_pnl->node, fbinfo_pnl->fix.id); | ||
1643 | |||
1644 | /* create device files */ | 1673 | /* create device files */ |
1645 | 1674 | ||
1646 | ret = device_create_file(dev, &dev_attr_crt_src); | 1675 | ret = device_create_file(dev, &dev_attr_crt_src); |
1647 | if (ret) | 1676 | if (ret) |
1648 | goto crtsrc_fail; | 1677 | goto err_started_panel; |
1649 | 1678 | ||
1650 | ret = device_create_file(dev, &dev_attr_fbregs_pnl); | 1679 | ret = device_create_file(dev, &dev_attr_fbregs_pnl); |
1651 | if (ret) | 1680 | if (ret) |
1652 | goto fbregs_pnl_fail; | 1681 | goto err_attached_crtsrc_file; |
1653 | 1682 | ||
1654 | ret = device_create_file(dev, &dev_attr_fbregs_crt); | 1683 | ret = device_create_file(dev, &dev_attr_fbregs_crt); |
1655 | if (ret) | 1684 | if (ret) |
1656 | goto fbregs_crt_fail; | 1685 | goto err_attached_pnlregs_file; |
1657 | 1686 | ||
1658 | /* we registered, return ok */ | 1687 | /* we registered, return ok */ |
1659 | return 0; | 1688 | return 0; |
1660 | 1689 | ||
1661 | fbregs_crt_fail: | 1690 | err_attached_pnlregs_file: |
1662 | device_remove_file(dev, &dev_attr_fbregs_pnl); | 1691 | device_remove_file(dev, &dev_attr_fbregs_pnl); |
1663 | 1692 | ||
1664 | fbregs_pnl_fail: | 1693 | err_attached_crtsrc_file: |
1665 | device_remove_file(dev, &dev_attr_crt_src); | 1694 | device_remove_file(dev, &dev_attr_crt_src); |
1666 | 1695 | ||
1667 | crtsrc_fail: | 1696 | err_started_panel: |
1668 | unregister_framebuffer(fbinfo_pnl); | 1697 | unregister_framebuffer(info->fb[HEAD_PANEL]); |
1698 | sm501_free_init_fb(info, HEAD_PANEL); | ||
1669 | 1699 | ||
1670 | register_pnl_fail: | 1700 | err_started_crt: |
1671 | unregister_framebuffer(fbinfo_crt); | 1701 | unregister_framebuffer(info->fb[HEAD_CRT]); |
1702 | sm501_free_init_fb(info, HEAD_CRT); | ||
1672 | 1703 | ||
1673 | register_crt_fail: | 1704 | err_started: |
1674 | sm501fb_stop(info); | 1705 | sm501fb_stop(info); |
1675 | 1706 | ||
1676 | sm501fb_start_fail: | 1707 | err_probed_panel: |
1677 | sm501fb_info_release(info); | 1708 | framebuffer_release(info->fb[HEAD_PANEL]); |
1678 | 1709 | ||
1679 | sm501fb_alloc_fail: | 1710 | err_probed_crt: |
1680 | framebuffer_release(fbinfo_pnl); | 1711 | framebuffer_release(info->fb[HEAD_CRT]); |
1681 | 1712 | ||
1682 | fbinfo_crt_alloc_fail: | 1713 | err_alloc: |
1683 | framebuffer_release(fbinfo_crt); | 1714 | kfree(info); |
1684 | 1715 | ||
1685 | return ret; | 1716 | return ret; |
1686 | } | 1717 | } |
@@ -1699,11 +1730,14 @@ static int sm501fb_remove(struct platform_device *pdev) | |||
1699 | device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); | 1730 | device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); |
1700 | device_remove_file(&pdev->dev, &dev_attr_crt_src); | 1731 | device_remove_file(&pdev->dev, &dev_attr_crt_src); |
1701 | 1732 | ||
1733 | sm501_free_init_fb(info, HEAD_CRT); | ||
1734 | sm501_free_init_fb(info, HEAD_PANEL); | ||
1735 | |||
1702 | unregister_framebuffer(fbinfo_crt); | 1736 | unregister_framebuffer(fbinfo_crt); |
1703 | unregister_framebuffer(fbinfo_pnl); | 1737 | unregister_framebuffer(fbinfo_pnl); |
1704 | 1738 | ||
1705 | sm501fb_stop(info); | 1739 | sm501fb_stop(info); |
1706 | sm501fb_info_release(info); | 1740 | kfree(info); |
1707 | 1741 | ||
1708 | framebuffer_release(fbinfo_pnl); | 1742 | framebuffer_release(fbinfo_pnl); |
1709 | framebuffer_release(fbinfo_crt); | 1743 | framebuffer_release(fbinfo_crt); |