aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sm501fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/sm501fb.c')
-rw-r--r--drivers/video/sm501fb.c264
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
1236static 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
1269static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) 1247static 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
1411static void sm501fb_info_release(struct sm501fb_info *info)
1412{
1413 kfree(info);
1414}
1415
1416static int sm501fb_init_fb(struct fb_info *fb, 1392static 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 = {
1557static char driver_name_crt[] = "sm501fb-crt"; 1533static char driver_name_crt[] = "sm501fb-crt";
1558static char driver_name_pnl[] = "sm501fb-panel"; 1534static char driver_name_pnl[] = "sm501fb-panel";
1559 1535
1560static int __init sm501fb_probe(struct platform_device *pdev) 1536static 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
1570static 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
1578static 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
1606static 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: 1690err_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: 1693err_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: 1696err_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: 1700err_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: 1704err_started:
1674 sm501fb_stop(info); 1705 sm501fb_stop(info);
1675 1706
1676 sm501fb_start_fail: 1707err_probed_panel:
1677 sm501fb_info_release(info); 1708 framebuffer_release(info->fb[HEAD_PANEL]);
1678 1709
1679 sm501fb_alloc_fail: 1710err_probed_crt:
1680 framebuffer_release(fbinfo_pnl); 1711 framebuffer_release(info->fb[HEAD_CRT]);
1681 1712
1682 fbinfo_crt_alloc_fail: 1713err_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);