diff options
Diffstat (limited to 'drivers/video/sm501fb.c')
-rw-r--r-- | drivers/video/sm501fb.c | 329 |
1 files changed, 206 insertions, 123 deletions
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 15d4a768b1f6..f94ae84a58cd 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c | |||
@@ -48,10 +48,15 @@ enum sm501_controller { | |||
48 | HEAD_PANEL = 1, | 48 | HEAD_PANEL = 1, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | /* SM501 memory address */ | 51 | /* SM501 memory address. |
52 | * | ||
53 | * This structure is used to track memory usage within the SM501 framebuffer | ||
54 | * allocation. The sm_addr field is stored as an offset as it is often used | ||
55 | * against both the physical and mapped addresses. | ||
56 | */ | ||
52 | struct sm501_mem { | 57 | struct sm501_mem { |
53 | unsigned long size; | 58 | unsigned long size; |
54 | unsigned long sm_addr; | 59 | unsigned long sm_addr; /* offset from base of sm501 fb. */ |
55 | void __iomem *k_addr; | 60 | void __iomem *k_addr; |
56 | }; | 61 | }; |
57 | 62 | ||
@@ -142,31 +147,68 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) | |||
142 | static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | 147 | static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, |
143 | unsigned int why, size_t size) | 148 | unsigned int why, size_t size) |
144 | { | 149 | { |
145 | unsigned int ptr = 0; | 150 | struct sm501fb_par *par; |
151 | struct fb_info *fbi; | ||
152 | unsigned int ptr; | ||
153 | unsigned int end; | ||
146 | 154 | ||
147 | switch (why) { | 155 | switch (why) { |
148 | case SM501_MEMF_CURSOR: | 156 | case SM501_MEMF_CURSOR: |
149 | ptr = inf->fbmem_len - size; | 157 | ptr = inf->fbmem_len - size; |
150 | inf->fbmem_len = ptr; | 158 | inf->fbmem_len = ptr; /* adjust available memory. */ |
151 | break; | 159 | break; |
152 | 160 | ||
153 | case SM501_MEMF_PANEL: | 161 | case SM501_MEMF_PANEL: |
154 | ptr = inf->fbmem_len - size; | 162 | ptr = inf->fbmem_len - size; |
155 | if (ptr < inf->fb[0]->fix.smem_len) | 163 | fbi = inf->fb[HEAD_CRT]; |
164 | |||
165 | /* round down, some programs such as directfb do not draw | ||
166 | * 0,0 correctly unless the start is aligned to a page start. | ||
167 | */ | ||
168 | |||
169 | if (ptr > 0) | ||
170 | ptr &= ~(PAGE_SIZE - 1); | ||
171 | |||
172 | if (fbi && ptr < fbi->fix.smem_len) | ||
173 | return -ENOMEM; | ||
174 | |||
175 | if (ptr < 0) | ||
156 | return -ENOMEM; | 176 | return -ENOMEM; |
157 | 177 | ||
158 | break; | 178 | break; |
159 | 179 | ||
160 | case SM501_MEMF_CRT: | 180 | case SM501_MEMF_CRT: |
161 | ptr = 0; | 181 | ptr = 0; |
182 | |||
183 | /* check to see if we have panel memory allocated | ||
184 | * which would put an limit on available memory. */ | ||
185 | |||
186 | fbi = inf->fb[HEAD_PANEL]; | ||
187 | if (fbi) { | ||
188 | par = fbi->par; | ||
189 | end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len; | ||
190 | } else | ||
191 | end = inf->fbmem_len; | ||
192 | |||
193 | if ((ptr + size) > end) | ||
194 | return -ENOMEM; | ||
195 | |||
162 | break; | 196 | break; |
163 | 197 | ||
164 | case SM501_MEMF_ACCEL: | 198 | case SM501_MEMF_ACCEL: |
165 | ptr = inf->fb[0]->fix.smem_len; | 199 | fbi = inf->fb[HEAD_CRT]; |
200 | ptr = fbi ? fbi->fix.smem_len : 0; | ||
201 | |||
202 | fbi = inf->fb[HEAD_PANEL]; | ||
203 | if (fbi) { | ||
204 | par = fbi->par; | ||
205 | end = par->screen.sm_addr; | ||
206 | } else | ||
207 | end = inf->fbmem_len; | ||
166 | 208 | ||
167 | if ((ptr + size) > | 209 | if ((ptr + size) > end) |
168 | (inf->fb[1]->fix.smem_start - inf->fbmem_res->start)) | ||
169 | return -ENOMEM; | 210 | return -ENOMEM; |
211 | |||
170 | break; | 212 | break; |
171 | 213 | ||
172 | default: | 214 | default: |
@@ -663,15 +705,25 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) | |||
663 | sm501fb_sync_regs(fbi); | 705 | sm501fb_sync_regs(fbi); |
664 | mdelay(10); | 706 | mdelay(10); |
665 | 707 | ||
708 | /* VBIASEN */ | ||
709 | |||
666 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { | 710 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { |
667 | control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ | 711 | if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN) |
712 | control &= ~SM501_DC_PANEL_CONTROL_BIAS; | ||
713 | else | ||
714 | control |= SM501_DC_PANEL_CONTROL_BIAS; | ||
715 | |||
668 | writel(control, ctrl_reg); | 716 | writel(control, ctrl_reg); |
669 | sm501fb_sync_regs(fbi); | 717 | sm501fb_sync_regs(fbi); |
670 | mdelay(10); | 718 | mdelay(10); |
671 | } | 719 | } |
672 | 720 | ||
673 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { | 721 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { |
674 | control |= SM501_DC_PANEL_CONTROL_FPEN; | 722 | if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN) |
723 | control &= ~SM501_DC_PANEL_CONTROL_FPEN; | ||
724 | else | ||
725 | control |= SM501_DC_PANEL_CONTROL_FPEN; | ||
726 | |||
675 | writel(control, ctrl_reg); | 727 | writel(control, ctrl_reg); |
676 | sm501fb_sync_regs(fbi); | 728 | sm501fb_sync_regs(fbi); |
677 | mdelay(10); | 729 | mdelay(10); |
@@ -679,14 +731,22 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) | |||
679 | } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { | 731 | } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { |
680 | /* disable panel power */ | 732 | /* disable panel power */ |
681 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { | 733 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { |
682 | control &= ~SM501_DC_PANEL_CONTROL_FPEN; | 734 | if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN) |
735 | control |= SM501_DC_PANEL_CONTROL_FPEN; | ||
736 | else | ||
737 | control &= ~SM501_DC_PANEL_CONTROL_FPEN; | ||
738 | |||
683 | writel(control, ctrl_reg); | 739 | writel(control, ctrl_reg); |
684 | sm501fb_sync_regs(fbi); | 740 | sm501fb_sync_regs(fbi); |
685 | mdelay(10); | 741 | mdelay(10); |
686 | } | 742 | } |
687 | 743 | ||
688 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { | 744 | if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { |
689 | control &= ~SM501_DC_PANEL_CONTROL_BIAS; | 745 | if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN) |
746 | control |= SM501_DC_PANEL_CONTROL_BIAS; | ||
747 | else | ||
748 | control &= ~SM501_DC_PANEL_CONTROL_BIAS; | ||
749 | |||
690 | writel(control, ctrl_reg); | 750 | writel(control, ctrl_reg); |
691 | sm501fb_sync_regs(fbi); | 751 | sm501fb_sync_regs(fbi); |
692 | mdelay(10); | 752 | mdelay(10); |
@@ -1210,39 +1270,6 @@ static struct fb_ops sm501fb_ops_pnl = { | |||
1210 | .fb_imageblit = cfb_imageblit, | 1270 | .fb_imageblit = cfb_imageblit, |
1211 | }; | 1271 | }; |
1212 | 1272 | ||
1213 | /* sm501fb_info_alloc | ||
1214 | * | ||
1215 | * creates and initialises an sm501fb_info structure | ||
1216 | */ | ||
1217 | |||
1218 | static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt, | ||
1219 | struct fb_info *fbinfo_pnl) | ||
1220 | { | ||
1221 | struct sm501fb_info *info; | ||
1222 | struct sm501fb_par *par; | ||
1223 | |||
1224 | info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); | ||
1225 | if (info) { | ||
1226 | /* set the references back */ | ||
1227 | |||
1228 | par = fbinfo_crt->par; | ||
1229 | par->info = info; | ||
1230 | par->head = HEAD_CRT; | ||
1231 | fbinfo_crt->pseudo_palette = &par->pseudo_palette; | ||
1232 | |||
1233 | par = fbinfo_pnl->par; | ||
1234 | par->info = info; | ||
1235 | par->head = HEAD_PANEL; | ||
1236 | fbinfo_pnl->pseudo_palette = &par->pseudo_palette; | ||
1237 | |||
1238 | /* store the two fbs into our info */ | ||
1239 | info->fb[HEAD_CRT] = fbinfo_crt; | ||
1240 | info->fb[HEAD_PANEL] = fbinfo_pnl; | ||
1241 | } | ||
1242 | |||
1243 | return info; | ||
1244 | } | ||
1245 | |||
1246 | /* sm501_init_cursor | 1273 | /* sm501_init_cursor |
1247 | * | 1274 | * |
1248 | * initialise hw cursor parameters | 1275 | * initialise hw cursor parameters |
@@ -1250,10 +1277,16 @@ static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt, | |||
1250 | 1277 | ||
1251 | static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) | 1278 | static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) |
1252 | { | 1279 | { |
1253 | struct sm501fb_par *par = fbi->par; | 1280 | struct sm501fb_par *par; |
1254 | struct sm501fb_info *info = par->info; | 1281 | struct sm501fb_info *info; |
1255 | int ret; | 1282 | int ret; |
1256 | 1283 | ||
1284 | if (fbi == NULL) | ||
1285 | return 0; | ||
1286 | |||
1287 | par = fbi->par; | ||
1288 | info = par->info; | ||
1289 | |||
1257 | par->cursor_regs = info->regs + reg_base; | 1290 | par->cursor_regs = info->regs + reg_base; |
1258 | 1291 | ||
1259 | ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); | 1292 | ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); |
@@ -1281,13 +1314,10 @@ static int sm501fb_start(struct sm501fb_info *info, | |||
1281 | struct platform_device *pdev) | 1314 | struct platform_device *pdev) |
1282 | { | 1315 | { |
1283 | struct resource *res; | 1316 | struct resource *res; |
1284 | struct device *dev; | 1317 | struct device *dev = &pdev->dev; |
1285 | int k; | 1318 | int k; |
1286 | int ret; | 1319 | int ret; |
1287 | 1320 | ||
1288 | info->dev = dev = &pdev->dev; | ||
1289 | platform_set_drvdata(pdev, info); | ||
1290 | |||
1291 | info->irq = ret = platform_get_irq(pdev, 0); | 1321 | info->irq = ret = platform_get_irq(pdev, 0); |
1292 | if (ret < 0) { | 1322 | if (ret < 0) { |
1293 | /* we currently do not use the IRQ */ | 1323 | /* we currently do not use the IRQ */ |
@@ -1390,11 +1420,6 @@ static void sm501fb_stop(struct sm501fb_info *info) | |||
1390 | kfree(info->regs_res); | 1420 | kfree(info->regs_res); |
1391 | } | 1421 | } |
1392 | 1422 | ||
1393 | static void sm501fb_info_release(struct sm501fb_info *info) | ||
1394 | { | ||
1395 | kfree(info); | ||
1396 | } | ||
1397 | |||
1398 | static int sm501fb_init_fb(struct fb_info *fb, | 1423 | static int sm501fb_init_fb(struct fb_info *fb, |
1399 | enum sm501_controller head, | 1424 | enum sm501_controller head, |
1400 | const char *fbname) | 1425 | const char *fbname) |
@@ -1539,36 +1564,93 @@ static struct sm501_platdata_fb sm501fb_def_pdata = { | |||
1539 | static char driver_name_crt[] = "sm501fb-crt"; | 1564 | static char driver_name_crt[] = "sm501fb-crt"; |
1540 | static char driver_name_pnl[] = "sm501fb-panel"; | 1565 | static char driver_name_pnl[] = "sm501fb-panel"; |
1541 | 1566 | ||
1542 | static int __init sm501fb_probe(struct platform_device *pdev) | 1567 | static int __devinit sm501fb_probe_one(struct sm501fb_info *info, |
1568 | enum sm501_controller head) | ||
1543 | { | 1569 | { |
1544 | struct sm501fb_info *info; | 1570 | unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel"; |
1545 | struct device *dev = &pdev->dev; | 1571 | struct sm501_platdata_fbsub *pd; |
1546 | struct fb_info *fbinfo_crt; | 1572 | struct sm501fb_par *par; |
1547 | struct fb_info *fbinfo_pnl; | 1573 | struct fb_info *fbi; |
1548 | int ret; | ||
1549 | 1574 | ||
1550 | /* allocate our framebuffers */ | 1575 | pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl; |
1576 | |||
1577 | /* Do not initialise if we've not been given any platform data */ | ||
1578 | if (pd == NULL) { | ||
1579 | dev_info(info->dev, "no data for fb %s (disabled)\n", name); | ||
1580 | return 0; | ||
1581 | } | ||
1551 | 1582 | ||
1552 | fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev); | 1583 | fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev); |
1553 | if (fbinfo_crt == NULL) { | 1584 | if (fbi == NULL) { |
1554 | dev_err(dev, "cannot allocate crt framebuffer\n"); | 1585 | dev_err(info->dev, "cannot allocate %s framebuffer\n", name); |
1555 | return -ENOMEM; | 1586 | return -ENOMEM; |
1556 | } | 1587 | } |
1557 | 1588 | ||
1558 | fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev); | 1589 | par = fbi->par; |
1559 | if (fbinfo_pnl == NULL) { | 1590 | par->info = info; |
1560 | dev_err(dev, "cannot allocate panel framebuffer\n"); | 1591 | par->head = head; |
1561 | ret = -ENOMEM; | 1592 | fbi->pseudo_palette = &par->pseudo_palette; |
1562 | goto fbinfo_crt_alloc_fail; | 1593 | |
1594 | info->fb[head] = fbi; | ||
1595 | |||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | /* Free up anything allocated by sm501fb_init_fb */ | ||
1600 | |||
1601 | static void sm501_free_init_fb(struct sm501fb_info *info, | ||
1602 | enum sm501_controller head) | ||
1603 | { | ||
1604 | struct fb_info *fbi = info->fb[head]; | ||
1605 | |||
1606 | fb_dealloc_cmap(&fbi->cmap); | ||
1607 | } | ||
1608 | |||
1609 | static int __devinit sm501fb_start_one(struct sm501fb_info *info, | ||
1610 | enum sm501_controller head, | ||
1611 | const char *drvname) | ||
1612 | { | ||
1613 | struct fb_info *fbi = info->fb[head]; | ||
1614 | int ret; | ||
1615 | |||
1616 | if (!fbi) | ||
1617 | return 0; | ||
1618 | |||
1619 | ret = sm501fb_init_fb(info->fb[head], head, drvname); | ||
1620 | if (ret) { | ||
1621 | dev_err(info->dev, "cannot initialise fb %s\n", drvname); | ||
1622 | return ret; | ||
1623 | } | ||
1624 | |||
1625 | ret = register_framebuffer(info->fb[head]); | ||
1626 | if (ret) { | ||
1627 | dev_err(info->dev, "failed to register fb %s\n", drvname); | ||
1628 | sm501_free_init_fb(info, head); | ||
1629 | return ret; | ||
1563 | } | 1630 | } |
1564 | 1631 | ||
1565 | info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl); | 1632 | dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id); |
1566 | if (info == NULL) { | 1633 | |
1567 | dev_err(dev, "cannot allocate par\n"); | 1634 | return 0; |
1568 | ret = -ENOMEM; | 1635 | } |
1569 | goto sm501fb_alloc_fail; | 1636 | |
1637 | static int __devinit sm501fb_probe(struct platform_device *pdev) | ||
1638 | { | ||
1639 | struct sm501fb_info *info; | ||
1640 | struct device *dev = &pdev->dev; | ||
1641 | int ret; | ||
1642 | |||
1643 | /* allocate our framebuffers */ | ||
1644 | |||
1645 | info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); | ||
1646 | if (!info) { | ||
1647 | dev_err(dev, "failed to allocate state\n"); | ||
1648 | return -ENOMEM; | ||
1570 | } | 1649 | } |
1571 | 1650 | ||
1651 | info->dev = dev = &pdev->dev; | ||
1652 | platform_set_drvdata(pdev, info); | ||
1653 | |||
1572 | if (dev->parent->platform_data) { | 1654 | if (dev->parent->platform_data) { |
1573 | struct sm501_platdata *pd = dev->parent->platform_data; | 1655 | struct sm501_platdata *pd = dev->parent->platform_data; |
1574 | info->pdata = pd->fb; | 1656 | info->pdata = pd->fb; |
@@ -1579,90 +1661,88 @@ static int __init sm501fb_probe(struct platform_device *pdev) | |||
1579 | info->pdata = &sm501fb_def_pdata; | 1661 | info->pdata = &sm501fb_def_pdata; |
1580 | } | 1662 | } |
1581 | 1663 | ||
1582 | /* start the framebuffers */ | 1664 | /* probe for the presence of each panel */ |
1583 | 1665 | ||
1584 | ret = sm501fb_start(info, pdev); | 1666 | ret = sm501fb_probe_one(info, HEAD_CRT); |
1585 | if (ret) { | 1667 | if (ret < 0) { |
1586 | dev_err(dev, "cannot initialise SM501\n"); | 1668 | dev_err(dev, "failed to probe CRT\n"); |
1587 | goto sm501fb_start_fail; | 1669 | goto err_alloc; |
1588 | } | 1670 | } |
1589 | 1671 | ||
1590 | /* CRT framebuffer setup */ | 1672 | ret = sm501fb_probe_one(info, HEAD_PANEL); |
1673 | if (ret < 0) { | ||
1674 | dev_err(dev, "failed to probe PANEL\n"); | ||
1675 | goto err_probed_crt; | ||
1676 | } | ||
1591 | 1677 | ||
1592 | ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt); | 1678 | if (info->fb[HEAD_PANEL] == NULL && |
1593 | if (ret) { | 1679 | info->fb[HEAD_CRT] == NULL) { |
1594 | dev_err(dev, "cannot initialise CRT fb\n"); | 1680 | dev_err(dev, "no framebuffers found\n"); |
1595 | goto sm501fb_start_fail; | 1681 | goto err_alloc; |
1596 | } | 1682 | } |
1597 | 1683 | ||
1598 | /* Panel framebuffer setup */ | 1684 | /* get the resources for both of the framebuffers */ |
1599 | 1685 | ||
1600 | ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl); | 1686 | ret = sm501fb_start(info, pdev); |
1601 | if (ret) { | 1687 | if (ret) { |
1602 | dev_err(dev, "cannot initialise Panel fb\n"); | 1688 | dev_err(dev, "cannot initialise SM501\n"); |
1603 | goto sm501fb_start_fail; | 1689 | goto err_probed_panel; |
1604 | } | 1690 | } |
1605 | 1691 | ||
1606 | /* register framebuffers */ | 1692 | ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt); |
1607 | 1693 | if (ret) { | |
1608 | ret = register_framebuffer(fbinfo_crt); | 1694 | dev_err(dev, "failed to start CRT\n"); |
1609 | if (ret < 0) { | 1695 | goto err_started; |
1610 | dev_err(dev, "failed to register CRT fb (%d)\n", ret); | ||
1611 | goto register_crt_fail; | ||
1612 | } | 1696 | } |
1613 | 1697 | ||
1614 | ret = register_framebuffer(fbinfo_pnl); | 1698 | ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl); |
1615 | if (ret < 0) { | 1699 | if (ret) { |
1616 | dev_err(dev, "failed to register panel fb (%d)\n", ret); | 1700 | dev_err(dev, "failed to start Panel\n"); |
1617 | goto register_pnl_fail; | 1701 | goto err_started_crt; |
1618 | } | 1702 | } |
1619 | 1703 | ||
1620 | dev_info(dev, "fb%d: %s frame buffer device\n", | ||
1621 | fbinfo_crt->node, fbinfo_crt->fix.id); | ||
1622 | |||
1623 | dev_info(dev, "fb%d: %s frame buffer device\n", | ||
1624 | fbinfo_pnl->node, fbinfo_pnl->fix.id); | ||
1625 | |||
1626 | /* create device files */ | 1704 | /* create device files */ |
1627 | 1705 | ||
1628 | ret = device_create_file(dev, &dev_attr_crt_src); | 1706 | ret = device_create_file(dev, &dev_attr_crt_src); |
1629 | if (ret) | 1707 | if (ret) |
1630 | goto crtsrc_fail; | 1708 | goto err_started_panel; |
1631 | 1709 | ||
1632 | ret = device_create_file(dev, &dev_attr_fbregs_pnl); | 1710 | ret = device_create_file(dev, &dev_attr_fbregs_pnl); |
1633 | if (ret) | 1711 | if (ret) |
1634 | goto fbregs_pnl_fail; | 1712 | goto err_attached_crtsrc_file; |
1635 | 1713 | ||
1636 | ret = device_create_file(dev, &dev_attr_fbregs_crt); | 1714 | ret = device_create_file(dev, &dev_attr_fbregs_crt); |
1637 | if (ret) | 1715 | if (ret) |
1638 | goto fbregs_crt_fail; | 1716 | goto err_attached_pnlregs_file; |
1639 | 1717 | ||
1640 | /* we registered, return ok */ | 1718 | /* we registered, return ok */ |
1641 | return 0; | 1719 | return 0; |
1642 | 1720 | ||
1643 | fbregs_crt_fail: | 1721 | err_attached_pnlregs_file: |
1644 | device_remove_file(dev, &dev_attr_fbregs_pnl); | 1722 | device_remove_file(dev, &dev_attr_fbregs_pnl); |
1645 | 1723 | ||
1646 | fbregs_pnl_fail: | 1724 | err_attached_crtsrc_file: |
1647 | device_remove_file(dev, &dev_attr_crt_src); | 1725 | device_remove_file(dev, &dev_attr_crt_src); |
1648 | 1726 | ||
1649 | crtsrc_fail: | 1727 | err_started_panel: |
1650 | unregister_framebuffer(fbinfo_pnl); | 1728 | unregister_framebuffer(info->fb[HEAD_PANEL]); |
1729 | sm501_free_init_fb(info, HEAD_PANEL); | ||
1651 | 1730 | ||
1652 | register_pnl_fail: | 1731 | err_started_crt: |
1653 | unregister_framebuffer(fbinfo_crt); | 1732 | unregister_framebuffer(info->fb[HEAD_CRT]); |
1733 | sm501_free_init_fb(info, HEAD_CRT); | ||
1654 | 1734 | ||
1655 | register_crt_fail: | 1735 | err_started: |
1656 | sm501fb_stop(info); | 1736 | sm501fb_stop(info); |
1657 | 1737 | ||
1658 | sm501fb_start_fail: | 1738 | err_probed_panel: |
1659 | sm501fb_info_release(info); | 1739 | framebuffer_release(info->fb[HEAD_PANEL]); |
1660 | 1740 | ||
1661 | sm501fb_alloc_fail: | 1741 | err_probed_crt: |
1662 | framebuffer_release(fbinfo_pnl); | 1742 | framebuffer_release(info->fb[HEAD_CRT]); |
1663 | 1743 | ||
1664 | fbinfo_crt_alloc_fail: | 1744 | err_alloc: |
1665 | framebuffer_release(fbinfo_crt); | 1745 | kfree(info); |
1666 | 1746 | ||
1667 | return ret; | 1747 | return ret; |
1668 | } | 1748 | } |
@@ -1681,11 +1761,14 @@ static int sm501fb_remove(struct platform_device *pdev) | |||
1681 | device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); | 1761 | device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); |
1682 | device_remove_file(&pdev->dev, &dev_attr_crt_src); | 1762 | device_remove_file(&pdev->dev, &dev_attr_crt_src); |
1683 | 1763 | ||
1764 | sm501_free_init_fb(info, HEAD_CRT); | ||
1765 | sm501_free_init_fb(info, HEAD_PANEL); | ||
1766 | |||
1684 | unregister_framebuffer(fbinfo_crt); | 1767 | unregister_framebuffer(fbinfo_crt); |
1685 | unregister_framebuffer(fbinfo_pnl); | 1768 | unregister_framebuffer(fbinfo_pnl); |
1686 | 1769 | ||
1687 | sm501fb_stop(info); | 1770 | sm501fb_stop(info); |
1688 | sm501fb_info_release(info); | 1771 | kfree(info); |
1689 | 1772 | ||
1690 | framebuffer_release(fbinfo_pnl); | 1773 | framebuffer_release(fbinfo_pnl); |
1691 | framebuffer_release(fbinfo_crt); | 1774 | framebuffer_release(fbinfo_crt); |