Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ben Dooks and committed by
Linus Torvalds
9b599fb2 206c5d69

+151 -117
+151 -117
drivers/video/sm501fb.c
··· 143 143 unsigned int why, size_t size) 144 144 { 145 145 unsigned int ptr = 0; 146 + unsigned int end; 147 + struct fb_info *fbi; 146 148 147 149 switch (why) { 148 150 case SM501_MEMF_CURSOR: ··· 154 152 155 153 case SM501_MEMF_PANEL: 156 154 ptr = inf->fbmem_len - size; 157 - if (ptr < inf->fb[0]->fix.smem_len) 155 + fbi = inf->fb[0]; 156 + 157 + if (fbi && ptr < fbi->fix.smem_len) 158 158 return -ENOMEM; 159 159 160 160 break; ··· 166 162 break; 167 163 168 164 case SM501_MEMF_ACCEL: 169 - ptr = inf->fb[0]->fix.smem_len; 165 + fbi = inf->fb[0]; 166 + ptr = fbi ? fbi->fix.smem_len : 0; 170 167 171 - if ((ptr + size) > 172 - (inf->fb[1]->fix.smem_start - inf->fbmem_res->start)) 168 + fbi = inf->fb[1]; 169 + if (fbi) 170 + end = (fbi->fix.smem_start - inf->fbmem_res->start); 171 + else 172 + end = inf->fbmem_len; 173 + 174 + if ((ptr + size) > end) 173 175 return -ENOMEM; 176 + 174 177 break; 175 178 176 179 default: ··· 1239 1228 .fb_imageblit = cfb_imageblit, 1240 1229 }; 1241 1230 1242 - /* sm501fb_info_alloc 1243 - * 1244 - * creates and initialises an sm501fb_info structure 1245 - */ 1246 - 1247 - static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt, 1248 - struct fb_info *fbinfo_pnl) 1249 - { 1250 - struct sm501fb_info *info; 1251 - struct sm501fb_par *par; 1252 - 1253 - info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); 1254 - if (info) { 1255 - /* set the references back */ 1256 - 1257 - par = fbinfo_crt->par; 1258 - par->info = info; 1259 - par->head = HEAD_CRT; 1260 - fbinfo_crt->pseudo_palette = &par->pseudo_palette; 1261 - 1262 - par = fbinfo_pnl->par; 1263 - par->info = info; 1264 - par->head = HEAD_PANEL; 1265 - fbinfo_pnl->pseudo_palette = &par->pseudo_palette; 1266 - 1267 - /* store the two fbs into our info */ 1268 - info->fb[HEAD_CRT] = fbinfo_crt; 1269 - info->fb[HEAD_PANEL] = fbinfo_pnl; 1270 - } 1271 - 1272 - return info; 1273 - } 1274 - 1275 1231 /* sm501_init_cursor 1276 1232 * 1277 1233 * initialise hw cursor parameters ··· 1246 1268 1247 1269 static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) 1248 1270 { 1249 - struct sm501fb_par *par = fbi->par; 1250 - struct sm501fb_info *info = par->info; 1271 + struct sm501fb_par *par; 1272 + struct sm501fb_info *info; 1251 1273 int ret; 1274 + 1275 + if (fbi == NULL) 1276 + return 0; 1277 + 1278 + par = fbi->par; 1279 + info = par->info; 1252 1280 1253 1281 par->cursor_regs = info->regs + reg_base; 1254 1282 ··· 1283 1299 struct platform_device *pdev) 1284 1300 { 1285 1301 struct resource *res; 1286 - struct device *dev; 1302 + struct device *dev = &pdev->dev; 1287 1303 int k; 1288 1304 int ret; 1289 - 1290 - info->dev = dev = &pdev->dev; 1291 - platform_set_drvdata(pdev, info); 1292 1305 1293 1306 info->irq = ret = platform_get_irq(pdev, 0); 1294 1307 if (ret < 0) { ··· 1387 1406 iounmap(info->regs); 1388 1407 release_resource(info->regs_res); 1389 1408 kfree(info->regs_res); 1390 - } 1391 - 1392 - static void sm501fb_info_release(struct sm501fb_info *info) 1393 - { 1394 - kfree(info); 1395 1409 } 1396 1410 1397 1411 static int sm501fb_init_fb(struct fb_info *fb, ··· 1533 1557 static char driver_name_crt[] = "sm501fb-crt"; 1534 1558 static char driver_name_pnl[] = "sm501fb-panel"; 1535 1559 1536 - static int __init sm501fb_probe(struct platform_device *pdev) 1560 + static int __devinit sm501fb_probe_one(struct sm501fb_info *info, 1561 + enum sm501_controller head) 1537 1562 { 1538 - struct sm501fb_info *info; 1539 - struct device *dev = &pdev->dev; 1540 - struct fb_info *fbinfo_crt; 1541 - struct fb_info *fbinfo_pnl; 1542 - int ret; 1563 + unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel"; 1564 + struct sm501_platdata_fbsub *pd; 1565 + struct sm501fb_par *par; 1566 + struct fb_info *fbi; 1543 1567 1544 - /* allocate our framebuffers */ 1568 + pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl; 1545 1569 1546 - fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev); 1547 - if (fbinfo_crt == NULL) { 1548 - dev_err(dev, "cannot allocate crt framebuffer\n"); 1570 + /* Do not initialise if we've not been given any platform data */ 1571 + if (pd == NULL) { 1572 + dev_info(info->dev, "no data for fb %s (disabled)\n", name); 1573 + return 0; 1574 + } 1575 + 1576 + fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev); 1577 + if (fbi == NULL) { 1578 + dev_err(info->dev, "cannot allocate %s framebuffer\n", name); 1549 1579 return -ENOMEM; 1550 1580 } 1551 1581 1552 - fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev); 1553 - if (fbinfo_pnl == NULL) { 1554 - dev_err(dev, "cannot allocate panel framebuffer\n"); 1555 - ret = -ENOMEM; 1556 - goto fbinfo_crt_alloc_fail; 1582 + par = fbi->par; 1583 + par->info = info; 1584 + par->head = head; 1585 + fbi->pseudo_palette = &par->pseudo_palette; 1586 + 1587 + info->fb[head] = fbi; 1588 + 1589 + return 0; 1590 + } 1591 + 1592 + /* Free up anything allocated by sm501fb_init_fb */ 1593 + 1594 + static void sm501_free_init_fb(struct sm501fb_info *info, 1595 + enum sm501_controller head) 1596 + { 1597 + struct fb_info *fbi = info->fb[head]; 1598 + 1599 + fb_dealloc_cmap(&fbi->cmap); 1600 + } 1601 + 1602 + static int __devinit sm501fb_start_one(struct sm501fb_info *info, 1603 + enum sm501_controller head, 1604 + const char *drvname) 1605 + { 1606 + struct fb_info *fbi = info->fb[head]; 1607 + int ret; 1608 + 1609 + if (!fbi) 1610 + return 0; 1611 + 1612 + ret = sm501fb_init_fb(info->fb[head], head, drvname); 1613 + if (ret) { 1614 + dev_err(info->dev, "cannot initialise fb %s\n", drvname); 1615 + return ret; 1557 1616 } 1558 1617 1559 - info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl); 1560 - if (info == NULL) { 1561 - dev_err(dev, "cannot allocate par\n"); 1562 - ret = -ENOMEM; 1563 - goto sm501fb_alloc_fail; 1618 + ret = register_framebuffer(info->fb[head]); 1619 + if (ret) { 1620 + dev_err(info->dev, "failed to register fb %s\n", drvname); 1621 + sm501_free_init_fb(info, head); 1622 + return ret; 1564 1623 } 1624 + 1625 + dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id); 1626 + 1627 + return 0; 1628 + } 1629 + 1630 + static int __devinit sm501fb_probe(struct platform_device *pdev) 1631 + { 1632 + struct sm501fb_info *info; 1633 + struct device *dev = &pdev->dev; 1634 + int ret; 1635 + 1636 + /* allocate our framebuffers */ 1637 + 1638 + info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); 1639 + if (!info) { 1640 + dev_err(dev, "failed to allocate state\n"); 1641 + return -ENOMEM; 1642 + } 1643 + 1644 + info->dev = dev = &pdev->dev; 1645 + platform_set_drvdata(pdev, info); 1565 1646 1566 1647 if (dev->parent->platform_data) { 1567 1648 struct sm501_platdata *pd = dev->parent->platform_data; ··· 1630 1597 info->pdata = &sm501fb_def_pdata; 1631 1598 } 1632 1599 1633 - /* start the framebuffers */ 1600 + /* probe for the presence of each panel */ 1601 + 1602 + ret = sm501fb_probe_one(info, HEAD_CRT); 1603 + if (ret < 0) { 1604 + dev_err(dev, "failed to probe CRT\n"); 1605 + goto err_alloc; 1606 + } 1607 + 1608 + ret = sm501fb_probe_one(info, HEAD_PANEL); 1609 + if (ret < 0) { 1610 + dev_err(dev, "failed to probe PANEL\n"); 1611 + goto err_probed_crt; 1612 + } 1613 + 1614 + if (info->fb[HEAD_PANEL] == NULL && 1615 + info->fb[HEAD_CRT] == NULL) { 1616 + dev_err(dev, "no framebuffers found\n"); 1617 + goto err_alloc; 1618 + } 1619 + 1620 + /* get the resources for both of the framebuffers */ 1634 1621 1635 1622 ret = sm501fb_start(info, pdev); 1636 1623 if (ret) { 1637 1624 dev_err(dev, "cannot initialise SM501\n"); 1638 - goto sm501fb_start_fail; 1625 + goto err_probed_panel; 1639 1626 } 1640 1627 1641 - /* CRT framebuffer setup */ 1642 - 1643 - ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt); 1628 + ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt); 1644 1629 if (ret) { 1645 - dev_err(dev, "cannot initialise CRT fb\n"); 1646 - goto sm501fb_start_fail; 1630 + dev_err(dev, "failed to start CRT\n"); 1631 + goto err_started; 1647 1632 } 1648 1633 1649 - /* Panel framebuffer setup */ 1650 - 1651 - ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl); 1634 + ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl); 1652 1635 if (ret) { 1653 - dev_err(dev, "cannot initialise Panel fb\n"); 1654 - goto sm501fb_start_fail; 1636 + dev_err(dev, "failed to start Panel\n"); 1637 + goto err_started_crt; 1655 1638 } 1656 - 1657 - /* register framebuffers */ 1658 - 1659 - ret = register_framebuffer(fbinfo_crt); 1660 - if (ret < 0) { 1661 - dev_err(dev, "failed to register CRT fb (%d)\n", ret); 1662 - goto register_crt_fail; 1663 - } 1664 - 1665 - ret = register_framebuffer(fbinfo_pnl); 1666 - if (ret < 0) { 1667 - dev_err(dev, "failed to register panel fb (%d)\n", ret); 1668 - goto register_pnl_fail; 1669 - } 1670 - 1671 - dev_info(dev, "fb%d: %s frame buffer device\n", 1672 - fbinfo_crt->node, fbinfo_crt->fix.id); 1673 - 1674 - dev_info(dev, "fb%d: %s frame buffer device\n", 1675 - fbinfo_pnl->node, fbinfo_pnl->fix.id); 1676 1639 1677 1640 /* create device files */ 1678 1641 1679 1642 ret = device_create_file(dev, &dev_attr_crt_src); 1680 1643 if (ret) 1681 - goto crtsrc_fail; 1644 + goto err_started_panel; 1682 1645 1683 1646 ret = device_create_file(dev, &dev_attr_fbregs_pnl); 1684 1647 if (ret) 1685 - goto fbregs_pnl_fail; 1648 + goto err_attached_crtsrc_file; 1686 1649 1687 1650 ret = device_create_file(dev, &dev_attr_fbregs_crt); 1688 1651 if (ret) 1689 - goto fbregs_crt_fail; 1652 + goto err_attached_pnlregs_file; 1690 1653 1691 1654 /* we registered, return ok */ 1692 1655 return 0; 1693 1656 1694 - fbregs_crt_fail: 1657 + err_attached_pnlregs_file: 1695 1658 device_remove_file(dev, &dev_attr_fbregs_pnl); 1696 1659 1697 - fbregs_pnl_fail: 1660 + err_attached_crtsrc_file: 1698 1661 device_remove_file(dev, &dev_attr_crt_src); 1699 1662 1700 - crtsrc_fail: 1701 - unregister_framebuffer(fbinfo_pnl); 1663 + err_started_panel: 1664 + unregister_framebuffer(info->fb[HEAD_PANEL]); 1665 + sm501_free_init_fb(info, HEAD_PANEL); 1702 1666 1703 - register_pnl_fail: 1704 - unregister_framebuffer(fbinfo_crt); 1667 + err_started_crt: 1668 + unregister_framebuffer(info->fb[HEAD_CRT]); 1669 + sm501_free_init_fb(info, HEAD_CRT); 1705 1670 1706 - register_crt_fail: 1671 + err_started: 1707 1672 sm501fb_stop(info); 1708 1673 1709 - sm501fb_start_fail: 1710 - sm501fb_info_release(info); 1674 + err_probed_panel: 1675 + framebuffer_release(info->fb[HEAD_PANEL]); 1711 1676 1712 - sm501fb_alloc_fail: 1713 - framebuffer_release(fbinfo_pnl); 1677 + err_probed_crt: 1678 + framebuffer_release(info->fb[HEAD_CRT]); 1714 1679 1715 - fbinfo_crt_alloc_fail: 1716 - framebuffer_release(fbinfo_crt); 1680 + err_alloc: 1681 + kfree(info); 1717 1682 1718 1683 return ret; 1719 1684 } ··· 1730 1699 device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); 1731 1700 device_remove_file(&pdev->dev, &dev_attr_crt_src); 1732 1701 1702 + sm501_free_init_fb(info, HEAD_CRT); 1703 + sm501_free_init_fb(info, HEAD_PANEL); 1704 + 1733 1705 unregister_framebuffer(fbinfo_crt); 1734 1706 unregister_framebuffer(fbinfo_pnl); 1735 1707 1736 1708 sm501fb_stop(info); 1737 - sm501fb_info_release(info); 1709 + kfree(info); 1738 1710 1739 1711 framebuffer_release(fbinfo_pnl); 1740 1712 framebuffer_release(fbinfo_crt);