diff options
-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); |