diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-14 14:24:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-14 14:24:32 -0400 |
commit | afa49791caae70cc3fd665a182eea61250795265 (patch) | |
tree | 5a1683ad60a9c789802cfb2ac657981a6e43410e | |
parent | 22fe9446e82f1fe4b59900db4599061384efb0ad (diff) | |
parent | c590cece75728a85ea06801df3ebad2d7ad8612c (diff) |
Merge branch 'fbmem'
* fbmem:
Further fbcon sanity checking
fbmem: fix remove_conflicting_framebuffers races
-rw-r--r-- | drivers/video/fbmem.c | 123 |
1 files changed, 71 insertions, 52 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ea16e654a9b6..5aac00eb1830 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -1537,8 +1537,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, | |||
1537 | return false; | 1537 | return false; |
1538 | } | 1538 | } |
1539 | 1539 | ||
1540 | static int do_unregister_framebuffer(struct fb_info *fb_info); | ||
1541 | |||
1540 | #define VGA_FB_PHYS 0xA0000 | 1542 | #define VGA_FB_PHYS 0xA0000 |
1541 | void remove_conflicting_framebuffers(struct apertures_struct *a, | 1543 | static void do_remove_conflicting_framebuffers(struct apertures_struct *a, |
1542 | const char *name, bool primary) | 1544 | const char *name, bool primary) |
1543 | { | 1545 | { |
1544 | int i; | 1546 | int i; |
@@ -1560,39 +1562,26 @@ void remove_conflicting_framebuffers(struct apertures_struct *a, | |||
1560 | printk(KERN_INFO "fb: conflicting fb hw usage " | 1562 | printk(KERN_INFO "fb: conflicting fb hw usage " |
1561 | "%s vs %s - removing generic driver\n", | 1563 | "%s vs %s - removing generic driver\n", |
1562 | name, registered_fb[i]->fix.id); | 1564 | name, registered_fb[i]->fix.id); |
1563 | unregister_framebuffer(registered_fb[i]); | 1565 | do_unregister_framebuffer(registered_fb[i]); |
1564 | } | 1566 | } |
1565 | } | 1567 | } |
1566 | } | 1568 | } |
1567 | EXPORT_SYMBOL(remove_conflicting_framebuffers); | ||
1568 | |||
1569 | /** | ||
1570 | * register_framebuffer - registers a frame buffer device | ||
1571 | * @fb_info: frame buffer info structure | ||
1572 | * | ||
1573 | * Registers a frame buffer device @fb_info. | ||
1574 | * | ||
1575 | * Returns negative errno on error, or zero for success. | ||
1576 | * | ||
1577 | */ | ||
1578 | 1569 | ||
1579 | int | 1570 | static int do_register_framebuffer(struct fb_info *fb_info) |
1580 | register_framebuffer(struct fb_info *fb_info) | ||
1581 | { | 1571 | { |
1582 | int i; | 1572 | int i; |
1583 | struct fb_event event; | 1573 | struct fb_event event; |
1584 | struct fb_videomode mode; | 1574 | struct fb_videomode mode; |
1585 | 1575 | ||
1586 | if (num_registered_fb == FB_MAX) | ||
1587 | return -ENXIO; | ||
1588 | |||
1589 | if (fb_check_foreignness(fb_info)) | 1576 | if (fb_check_foreignness(fb_info)) |
1590 | return -ENOSYS; | 1577 | return -ENOSYS; |
1591 | 1578 | ||
1592 | remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, | 1579 | do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, |
1593 | fb_is_primary_device(fb_info)); | 1580 | fb_is_primary_device(fb_info)); |
1594 | 1581 | ||
1595 | mutex_lock(®istration_lock); | 1582 | if (num_registered_fb == FB_MAX) |
1583 | return -ENXIO; | ||
1584 | |||
1596 | num_registered_fb++; | 1585 | num_registered_fb++; |
1597 | for (i = 0 ; i < FB_MAX; i++) | 1586 | for (i = 0 ; i < FB_MAX; i++) |
1598 | if (!registered_fb[i]) | 1587 | if (!registered_fb[i]) |
@@ -1635,7 +1624,6 @@ register_framebuffer(struct fb_info *fb_info) | |||
1635 | fb_var_to_videomode(&mode, &fb_info->var); | 1624 | fb_var_to_videomode(&mode, &fb_info->var); |
1636 | fb_add_videomode(&mode, &fb_info->modelist); | 1625 | fb_add_videomode(&mode, &fb_info->modelist); |
1637 | registered_fb[i] = fb_info; | 1626 | registered_fb[i] = fb_info; |
1638 | mutex_unlock(®istration_lock); | ||
1639 | 1627 | ||
1640 | event.info = fb_info; | 1628 | event.info = fb_info; |
1641 | if (!lock_fb_info(fb_info)) | 1629 | if (!lock_fb_info(fb_info)) |
@@ -1645,37 +1633,14 @@ register_framebuffer(struct fb_info *fb_info) | |||
1645 | return 0; | 1633 | return 0; |
1646 | } | 1634 | } |
1647 | 1635 | ||
1648 | 1636 | static int do_unregister_framebuffer(struct fb_info *fb_info) | |
1649 | /** | ||
1650 | * unregister_framebuffer - releases a frame buffer device | ||
1651 | * @fb_info: frame buffer info structure | ||
1652 | * | ||
1653 | * Unregisters a frame buffer device @fb_info. | ||
1654 | * | ||
1655 | * Returns negative errno on error, or zero for success. | ||
1656 | * | ||
1657 | * This function will also notify the framebuffer console | ||
1658 | * to release the driver. | ||
1659 | * | ||
1660 | * This is meant to be called within a driver's module_exit() | ||
1661 | * function. If this is called outside module_exit(), ensure | ||
1662 | * that the driver implements fb_open() and fb_release() to | ||
1663 | * check that no processes are using the device. | ||
1664 | */ | ||
1665 | |||
1666 | int | ||
1667 | unregister_framebuffer(struct fb_info *fb_info) | ||
1668 | { | 1637 | { |
1669 | struct fb_event event; | 1638 | struct fb_event event; |
1670 | int i, ret = 0; | 1639 | int i, ret = 0; |
1671 | 1640 | ||
1672 | mutex_lock(®istration_lock); | ||
1673 | i = fb_info->node; | 1641 | i = fb_info->node; |
1674 | if (!registered_fb[i]) { | 1642 | if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) |
1675 | ret = -EINVAL; | 1643 | return -EINVAL; |
1676 | goto done; | ||
1677 | } | ||
1678 | |||
1679 | 1644 | ||
1680 | if (!lock_fb_info(fb_info)) | 1645 | if (!lock_fb_info(fb_info)) |
1681 | return -ENODEV; | 1646 | return -ENODEV; |
@@ -1683,10 +1648,8 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1683 | ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); | 1648 | ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); |
1684 | unlock_fb_info(fb_info); | 1649 | unlock_fb_info(fb_info); |
1685 | 1650 | ||
1686 | if (ret) { | 1651 | if (ret) |
1687 | ret = -EINVAL; | 1652 | return -EINVAL; |
1688 | goto done; | ||
1689 | } | ||
1690 | 1653 | ||
1691 | if (fb_info->pixmap.addr && | 1654 | if (fb_info->pixmap.addr && |
1692 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | 1655 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) |
@@ -1701,8 +1664,64 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1701 | 1664 | ||
1702 | /* this may free fb info */ | 1665 | /* this may free fb info */ |
1703 | put_fb_info(fb_info); | 1666 | put_fb_info(fb_info); |
1704 | done: | 1667 | return 0; |
1668 | } | ||
1669 | |||
1670 | void remove_conflicting_framebuffers(struct apertures_struct *a, | ||
1671 | const char *name, bool primary) | ||
1672 | { | ||
1673 | mutex_lock(®istration_lock); | ||
1674 | do_remove_conflicting_framebuffers(a, name, primary); | ||
1675 | mutex_unlock(®istration_lock); | ||
1676 | } | ||
1677 | EXPORT_SYMBOL(remove_conflicting_framebuffers); | ||
1678 | |||
1679 | /** | ||
1680 | * register_framebuffer - registers a frame buffer device | ||
1681 | * @fb_info: frame buffer info structure | ||
1682 | * | ||
1683 | * Registers a frame buffer device @fb_info. | ||
1684 | * | ||
1685 | * Returns negative errno on error, or zero for success. | ||
1686 | * | ||
1687 | */ | ||
1688 | int | ||
1689 | register_framebuffer(struct fb_info *fb_info) | ||
1690 | { | ||
1691 | int ret; | ||
1692 | |||
1693 | mutex_lock(®istration_lock); | ||
1694 | ret = do_register_framebuffer(fb_info); | ||
1695 | mutex_unlock(®istration_lock); | ||
1696 | |||
1697 | return ret; | ||
1698 | } | ||
1699 | |||
1700 | /** | ||
1701 | * unregister_framebuffer - releases a frame buffer device | ||
1702 | * @fb_info: frame buffer info structure | ||
1703 | * | ||
1704 | * Unregisters a frame buffer device @fb_info. | ||
1705 | * | ||
1706 | * Returns negative errno on error, or zero for success. | ||
1707 | * | ||
1708 | * This function will also notify the framebuffer console | ||
1709 | * to release the driver. | ||
1710 | * | ||
1711 | * This is meant to be called within a driver's module_exit() | ||
1712 | * function. If this is called outside module_exit(), ensure | ||
1713 | * that the driver implements fb_open() and fb_release() to | ||
1714 | * check that no processes are using the device. | ||
1715 | */ | ||
1716 | int | ||
1717 | unregister_framebuffer(struct fb_info *fb_info) | ||
1718 | { | ||
1719 | int ret; | ||
1720 | |||
1721 | mutex_lock(®istration_lock); | ||
1722 | ret = do_unregister_framebuffer(fb_info); | ||
1705 | mutex_unlock(®istration_lock); | 1723 | mutex_unlock(®istration_lock); |
1724 | |||
1706 | return ret; | 1725 | return ret; |
1707 | } | 1726 | } |
1708 | 1727 | ||