|
25 | 25 | #include <linux/init.h> |
26 | 26 | #include <linux/linux_logo.h> |
27 | 27 | #include <linux/proc_fs.h> |
| 28 | +#include <linux/platform_device.h> |
28 | 29 | #include <linux/seq_file.h> |
29 | 30 | #include <linux/console.h> |
30 | 31 | #include <linux/kmod.h> |
@@ -1557,18 +1558,36 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, |
1557 | 1558 | /* check all firmware fbs and kick off if the base addr overlaps */ |
1558 | 1559 | for_each_registered_fb(i) { |
1559 | 1560 | struct apertures_struct *gen_aper; |
| 1561 | + struct device *device; |
1560 | 1562 |
|
1561 | 1563 | if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) |
1562 | 1564 | continue; |
1563 | 1565 |
|
1564 | 1566 | gen_aper = registered_fb[i]->apertures; |
| 1567 | + device = registered_fb[i]->device; |
1565 | 1568 | if (fb_do_apertures_overlap(gen_aper, a) || |
1566 | 1569 | (primary && gen_aper && gen_aper->count && |
1567 | 1570 | gen_aper->ranges[0].base == VGA_FB_PHYS)) { |
1568 | 1571 |
|
1569 | 1572 | printk(KERN_INFO "fb%d: switching to %s from %s\n", |
1570 | 1573 | i, name, registered_fb[i]->fix.id); |
1571 | | - do_unregister_framebuffer(registered_fb[i]); |
| 1574 | + |
| 1575 | + /* |
| 1576 | + * If we kick-out a firmware driver, we also want to remove |
| 1577 | + * the underlying platform device, such as simple-framebuffer, |
| 1578 | + * VESA, EFI, etc. A native driver will then be able to |
| 1579 | + * allocate the memory range. |
| 1580 | + * |
| 1581 | + * If it's not a platform device, at least print a warning. A |
| 1582 | + * fix would add code to remove the device from the system. |
| 1583 | + */ |
| 1584 | + if (dev_is_platform(device)) { |
| 1585 | + registered_fb[i]->forced_out = true; |
| 1586 | + platform_device_unregister(to_platform_device(device)); |
| 1587 | + } else { |
| 1588 | + pr_warn("fb%d: cannot remove device\n", i); |
| 1589 | + do_unregister_framebuffer(registered_fb[i]); |
| 1590 | + } |
1572 | 1591 | } |
1573 | 1592 | } |
1574 | 1593 | } |
@@ -1851,9 +1870,13 @@ EXPORT_SYMBOL(register_framebuffer); |
1851 | 1870 | void |
1852 | 1871 | unregister_framebuffer(struct fb_info *fb_info) |
1853 | 1872 | { |
1854 | | - mutex_lock(®istration_lock); |
| 1873 | + bool forced_out = fb_info->forced_out; |
| 1874 | + |
| 1875 | + if (!forced_out) |
| 1876 | + mutex_lock(®istration_lock); |
1855 | 1877 | do_unregister_framebuffer(fb_info); |
1856 | | - mutex_unlock(®istration_lock); |
| 1878 | + if (!forced_out) |
| 1879 | + mutex_unlock(®istration_lock); |
1857 | 1880 | } |
1858 | 1881 | EXPORT_SYMBOL(unregister_framebuffer); |
1859 | 1882 |
|
|
0 commit comments