aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r--drivers/video/fbmem.c300
1 files changed, 178 insertions, 122 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index b06647517c0e..5aac00eb1830 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -42,9 +42,34 @@
42 42
43#define FBPIXMAPSIZE (1024 * 8) 43#define FBPIXMAPSIZE (1024 * 8)
44 44
45static DEFINE_MUTEX(registration_lock);
45struct fb_info *registered_fb[FB_MAX] __read_mostly; 46struct fb_info *registered_fb[FB_MAX] __read_mostly;
46int num_registered_fb __read_mostly; 47int num_registered_fb __read_mostly;
47 48
49static struct fb_info *get_fb_info(unsigned int idx)
50{
51 struct fb_info *fb_info;
52
53 if (idx >= FB_MAX)
54 return ERR_PTR(-ENODEV);
55
56 mutex_lock(&registration_lock);
57 fb_info = registered_fb[idx];
58 if (fb_info)
59 atomic_inc(&fb_info->count);
60 mutex_unlock(&registration_lock);
61
62 return fb_info;
63}
64
65static void put_fb_info(struct fb_info *fb_info)
66{
67 if (!atomic_dec_and_test(&fb_info->count))
68 return;
69 if (fb_info->fbops->fb_destroy)
70 fb_info->fbops->fb_destroy(fb_info);
71}
72
48int lock_fb_info(struct fb_info *info) 73int lock_fb_info(struct fb_info *info)
49{ 74{
50 mutex_lock(&info->lock); 75 mutex_lock(&info->lock);
@@ -647,6 +672,7 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
647 672
648static void *fb_seq_start(struct seq_file *m, loff_t *pos) 673static void *fb_seq_start(struct seq_file *m, loff_t *pos)
649{ 674{
675 mutex_lock(&registration_lock);
650 return (*pos < FB_MAX) ? pos : NULL; 676 return (*pos < FB_MAX) ? pos : NULL;
651} 677}
652 678
@@ -658,6 +684,7 @@ static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
658 684
659static void fb_seq_stop(struct seq_file *m, void *v) 685static void fb_seq_stop(struct seq_file *m, void *v)
660{ 686{
687 mutex_unlock(&registration_lock);
661} 688}
662 689
663static int fb_seq_show(struct seq_file *m, void *v) 690static int fb_seq_show(struct seq_file *m, void *v)
@@ -690,16 +717,33 @@ static const struct file_operations fb_proc_fops = {
690 .release = seq_release, 717 .release = seq_release,
691}; 718};
692 719
693static ssize_t 720/*
694fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 721 * We hold a reference to the fb_info in file->private_data,
722 * but if the current registered fb has changed, we don't
723 * actually want to use it.
724 *
725 * So look up the fb_info using the inode minor number,
726 * and just verify it against the reference we have.
727 */
728static struct fb_info *file_fb_info(struct file *file)
695{ 729{
696 unsigned long p = *ppos;
697 struct inode *inode = file->f_path.dentry->d_inode; 730 struct inode *inode = file->f_path.dentry->d_inode;
698 int fbidx = iminor(inode); 731 int fbidx = iminor(inode);
699 struct fb_info *info = registered_fb[fbidx]; 732 struct fb_info *info = registered_fb[fbidx];
700 u32 *buffer, *dst; 733
701 u32 __iomem *src; 734 if (info != file->private_data)
702 int c, i, cnt = 0, err = 0; 735 info = NULL;
736 return info;
737}
738
739static ssize_t
740fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
741{
742 unsigned long p = *ppos;
743 struct fb_info *info = file_fb_info(file);
744 u8 *buffer, *dst;
745 u8 __iomem *src;
746 int c, cnt = 0, err = 0;
703 unsigned long total_size; 747 unsigned long total_size;
704 748
705 if (!info || ! info->screen_base) 749 if (!info || ! info->screen_base)
@@ -730,7 +774,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
730 if (!buffer) 774 if (!buffer)
731 return -ENOMEM; 775 return -ENOMEM;
732 776
733 src = (u32 __iomem *) (info->screen_base + p); 777 src = (u8 __iomem *) (info->screen_base + p);
734 778
735 if (info->fbops->fb_sync) 779 if (info->fbops->fb_sync)
736 info->fbops->fb_sync(info); 780 info->fbops->fb_sync(info);
@@ -738,17 +782,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
738 while (count) { 782 while (count) {
739 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 783 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
740 dst = buffer; 784 dst = buffer;
741 for (i = c >> 2; i--; ) 785 fb_memcpy_fromfb(dst, src, c);
742 *dst++ = fb_readl(src++); 786 dst += c;
743 if (c & 3) { 787 src += c;
744 u8 *dst8 = (u8 *) dst;
745 u8 __iomem *src8 = (u8 __iomem *) src;
746
747 for (i = c & 3; i--;)
748 *dst8++ = fb_readb(src8++);
749
750 src = (u32 __iomem *) src8;
751 }
752 788
753 if (copy_to_user(buf, buffer, c)) { 789 if (copy_to_user(buf, buffer, c)) {
754 err = -EFAULT; 790 err = -EFAULT;
@@ -769,12 +805,10 @@ static ssize_t
769fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 805fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
770{ 806{
771 unsigned long p = *ppos; 807 unsigned long p = *ppos;
772 struct inode *inode = file->f_path.dentry->d_inode; 808 struct fb_info *info = file_fb_info(file);
773 int fbidx = iminor(inode); 809 u8 *buffer, *src;
774 struct fb_info *info = registered_fb[fbidx]; 810 u8 __iomem *dst;
775 u32 *buffer, *src; 811 int c, cnt = 0, err = 0;
776 u32 __iomem *dst;
777 int c, i, cnt = 0, err = 0;
778 unsigned long total_size; 812 unsigned long total_size;
779 813
780 if (!info || !info->screen_base) 814 if (!info || !info->screen_base)
@@ -811,7 +845,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
811 if (!buffer) 845 if (!buffer)
812 return -ENOMEM; 846 return -ENOMEM;
813 847
814 dst = (u32 __iomem *) (info->screen_base + p); 848 dst = (u8 __iomem *) (info->screen_base + p);
815 849
816 if (info->fbops->fb_sync) 850 if (info->fbops->fb_sync)
817 info->fbops->fb_sync(info); 851 info->fbops->fb_sync(info);
@@ -825,19 +859,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
825 break; 859 break;
826 } 860 }
827 861
828 for (i = c >> 2; i--; ) 862 fb_memcpy_tofb(dst, src, c);
829 fb_writel(*src++, dst++); 863 dst += c;
830 864 src += c;
831 if (c & 3) {
832 u8 *src8 = (u8 *) src;
833 u8 __iomem *dst8 = (u8 __iomem *) dst;
834
835 for (i = c & 3; i--; )
836 fb_writeb(*src8++, dst8++);
837
838 dst = (u32 __iomem *) dst8;
839 }
840
841 *ppos += c; 865 *ppos += c;
842 buf += c; 866 buf += c;
843 cnt += c; 867 cnt += c;
@@ -877,13 +901,13 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
877 901
878 if ((err = info->fbops->fb_pan_display(var, info))) 902 if ((err = info->fbops->fb_pan_display(var, info)))
879 return err; 903 return err;
880 info->var.xoffset = var->xoffset; 904 info->var.xoffset = var->xoffset;
881 info->var.yoffset = var->yoffset; 905 info->var.yoffset = var->yoffset;
882 if (var->vmode & FB_VMODE_YWRAP) 906 if (var->vmode & FB_VMODE_YWRAP)
883 info->var.vmode |= FB_VMODE_YWRAP; 907 info->var.vmode |= FB_VMODE_YWRAP;
884 else 908 else
885 info->var.vmode &= ~FB_VMODE_YWRAP; 909 info->var.vmode &= ~FB_VMODE_YWRAP;
886 return 0; 910 return 0;
887} 911}
888 912
889static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, 913static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
@@ -1054,11 +1078,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1054 return -EFAULT; 1078 return -EFAULT;
1055 if (!lock_fb_info(info)) 1079 if (!lock_fb_info(info))
1056 return -ENODEV; 1080 return -ENODEV;
1057 acquire_console_sem(); 1081 console_lock();
1058 info->flags |= FBINFO_MISC_USEREVENT; 1082 info->flags |= FBINFO_MISC_USEREVENT;
1059 ret = fb_set_var(info, &var); 1083 ret = fb_set_var(info, &var);
1060 info->flags &= ~FBINFO_MISC_USEREVENT; 1084 info->flags &= ~FBINFO_MISC_USEREVENT;
1061 release_console_sem(); 1085 console_unlock();
1062 unlock_fb_info(info); 1086 unlock_fb_info(info);
1063 if (!ret && copy_to_user(argp, &var, sizeof(var))) 1087 if (!ret && copy_to_user(argp, &var, sizeof(var)))
1064 ret = -EFAULT; 1088 ret = -EFAULT;
@@ -1090,9 +1114,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1090 return -EFAULT; 1114 return -EFAULT;
1091 if (!lock_fb_info(info)) 1115 if (!lock_fb_info(info))
1092 return -ENODEV; 1116 return -ENODEV;
1093 acquire_console_sem(); 1117 console_lock();
1094 ret = fb_pan_display(info, &var); 1118 ret = fb_pan_display(info, &var);
1095 release_console_sem(); 1119 console_unlock();
1096 unlock_fb_info(info); 1120 unlock_fb_info(info);
1097 if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) 1121 if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
1098 return -EFAULT; 1122 return -EFAULT;
@@ -1137,11 +1161,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1137 case FBIOBLANK: 1161 case FBIOBLANK:
1138 if (!lock_fb_info(info)) 1162 if (!lock_fb_info(info))
1139 return -ENODEV; 1163 return -ENODEV;
1140 acquire_console_sem(); 1164 console_lock();
1141 info->flags |= FBINFO_MISC_USEREVENT; 1165 info->flags |= FBINFO_MISC_USEREVENT;
1142 ret = fb_blank(info, arg); 1166 ret = fb_blank(info, arg);
1143 info->flags &= ~FBINFO_MISC_USEREVENT; 1167 info->flags &= ~FBINFO_MISC_USEREVENT;
1144 release_console_sem(); 1168 console_unlock();
1145 unlock_fb_info(info); 1169 unlock_fb_info(info);
1146 break; 1170 break;
1147 default: 1171 default:
@@ -1159,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1159 1183
1160static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1184static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1161{ 1185{
1162 struct inode *inode = file->f_path.dentry->d_inode; 1186 struct fb_info *info = file_fb_info(file);
1163 int fbidx = iminor(inode);
1164 struct fb_info *info = registered_fb[fbidx];
1165 1187
1188 if (!info)
1189 return -ENODEV;
1166 return do_fb_ioctl(info, cmd, arg); 1190 return do_fb_ioctl(info, cmd, arg);
1167} 1191}
1168 1192
@@ -1283,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
1283static long fb_compat_ioctl(struct file *file, unsigned int cmd, 1307static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1284 unsigned long arg) 1308 unsigned long arg)
1285{ 1309{
1286 struct inode *inode = file->f_path.dentry->d_inode; 1310 struct fb_info *info = file_fb_info(file);
1287 int fbidx = iminor(inode); 1311 struct fb_ops *fb;
1288 struct fb_info *info = registered_fb[fbidx];
1289 struct fb_ops *fb = info->fbops;
1290 long ret = -ENOIOCTLCMD; 1312 long ret = -ENOIOCTLCMD;
1291 1313
1314 if (!info)
1315 return -ENODEV;
1316 fb = info->fbops;
1292 switch(cmd) { 1317 switch(cmd) {
1293 case FBIOGET_VSCREENINFO: 1318 case FBIOGET_VSCREENINFO:
1294 case FBIOPUT_VSCREENINFO: 1319 case FBIOPUT_VSCREENINFO:
@@ -1321,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1321static int 1346static int
1322fb_mmap(struct file *file, struct vm_area_struct * vma) 1347fb_mmap(struct file *file, struct vm_area_struct * vma)
1323{ 1348{
1324 int fbidx = iminor(file->f_path.dentry->d_inode); 1349 struct fb_info *info = file_fb_info(file);
1325 struct fb_info *info = registered_fb[fbidx]; 1350 struct fb_ops *fb;
1326 struct fb_ops *fb = info->fbops;
1327 unsigned long off; 1351 unsigned long off;
1328 unsigned long start; 1352 unsigned long start;
1329 u32 len; 1353 u32 len;
1330 1354
1355 if (!info)
1356 return -ENODEV;
1331 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1357 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1332 return -EINVAL; 1358 return -EINVAL;
1333 off = vma->vm_pgoff << PAGE_SHIFT; 1359 off = vma->vm_pgoff << PAGE_SHIFT;
1360 fb = info->fbops;
1334 if (!fb) 1361 if (!fb)
1335 return -ENODEV; 1362 return -ENODEV;
1336 mutex_lock(&info->mm_lock); 1363 mutex_lock(&info->mm_lock);
@@ -1379,14 +1406,16 @@ __releases(&info->lock)
1379 struct fb_info *info; 1406 struct fb_info *info;
1380 int res = 0; 1407 int res = 0;
1381 1408
1382 if (fbidx >= FB_MAX) 1409 info = get_fb_info(fbidx);
1383 return -ENODEV; 1410 if (!info) {
1384 info = registered_fb[fbidx];
1385 if (!info)
1386 request_module("fb%d", fbidx); 1411 request_module("fb%d", fbidx);
1387 info = registered_fb[fbidx]; 1412 info = get_fb_info(fbidx);
1388 if (!info) 1413 if (!info)
1389 return -ENODEV; 1414 return -ENODEV;
1415 }
1416 if (IS_ERR(info))
1417 return PTR_ERR(info);
1418
1390 mutex_lock(&info->lock); 1419 mutex_lock(&info->lock);
1391 if (!try_module_get(info->fbops->owner)) { 1420 if (!try_module_get(info->fbops->owner)) {
1392 res = -ENODEV; 1421 res = -ENODEV;
@@ -1404,6 +1433,8 @@ __releases(&info->lock)
1404#endif 1433#endif
1405out: 1434out:
1406 mutex_unlock(&info->lock); 1435 mutex_unlock(&info->lock);
1436 if (res)
1437 put_fb_info(info);
1407 return res; 1438 return res;
1408} 1439}
1409 1440
@@ -1419,6 +1450,7 @@ __releases(&info->lock)
1419 info->fbops->fb_release(info,1); 1450 info->fbops->fb_release(info,1);
1420 module_put(info->fbops->owner); 1451 module_put(info->fbops->owner);
1421 mutex_unlock(&info->lock); 1452 mutex_unlock(&info->lock);
1453 put_fb_info(info);
1422 return 0; 1454 return 0;
1423} 1455}
1424 1456
@@ -1439,6 +1471,7 @@ static const struct file_operations fb_fops = {
1439#ifdef CONFIG_FB_DEFERRED_IO 1471#ifdef CONFIG_FB_DEFERRED_IO
1440 .fsync = fb_deferred_io_fsync, 1472 .fsync = fb_deferred_io_fsync,
1441#endif 1473#endif
1474 .llseek = default_llseek,
1442}; 1475};
1443 1476
1444struct class *fb_class; 1477struct class *fb_class;
@@ -1475,7 +1508,7 @@ static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
1475 if (gen->base == hw->base) 1508 if (gen->base == hw->base)
1476 return true; 1509 return true;
1477 /* is the generic aperture base inside the hw base->hw base+size */ 1510 /* is the generic aperture base inside the hw base->hw base+size */
1478 if (gen->base > hw->base && gen->base <= hw->base + hw->size) 1511 if (gen->base > hw->base && gen->base < hw->base + hw->size)
1479 return true; 1512 return true;
1480 return false; 1513 return false;
1481} 1514}
@@ -1504,8 +1537,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena,
1504 return false; 1537 return false;
1505} 1538}
1506 1539
1540static int do_unregister_framebuffer(struct fb_info *fb_info);
1541
1507#define VGA_FB_PHYS 0xA0000 1542#define VGA_FB_PHYS 0xA0000
1508void remove_conflicting_framebuffers(struct apertures_struct *a, 1543static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
1509 const char *name, bool primary) 1544 const char *name, bool primary)
1510{ 1545{
1511 int i; 1546 int i;
@@ -1524,46 +1559,35 @@ void remove_conflicting_framebuffers(struct apertures_struct *a,
1524 (primary && gen_aper && gen_aper->count && 1559 (primary && gen_aper && gen_aper->count &&
1525 gen_aper->ranges[0].base == VGA_FB_PHYS)) { 1560 gen_aper->ranges[0].base == VGA_FB_PHYS)) {
1526 1561
1527 printk(KERN_ERR "fb: conflicting fb hw usage " 1562 printk(KERN_INFO "fb: conflicting fb hw usage "
1528 "%s vs %s - removing generic driver\n", 1563 "%s vs %s - removing generic driver\n",
1529 name, registered_fb[i]->fix.id); 1564 name, registered_fb[i]->fix.id);
1530 unregister_framebuffer(registered_fb[i]); 1565 do_unregister_framebuffer(registered_fb[i]);
1531 } 1566 }
1532 } 1567 }
1533} 1568}
1534EXPORT_SYMBOL(remove_conflicting_framebuffers);
1535
1536/**
1537 * register_framebuffer - registers a frame buffer device
1538 * @fb_info: frame buffer info structure
1539 *
1540 * Registers a frame buffer device @fb_info.
1541 *
1542 * Returns negative errno on error, or zero for success.
1543 *
1544 */
1545 1569
1546int 1570static int do_register_framebuffer(struct fb_info *fb_info)
1547register_framebuffer(struct fb_info *fb_info)
1548{ 1571{
1549 int i; 1572 int i;
1550 struct fb_event event; 1573 struct fb_event event;
1551 struct fb_videomode mode; 1574 struct fb_videomode mode;
1552 1575
1553 if (num_registered_fb == FB_MAX)
1554 return -ENXIO;
1555
1556 if (fb_check_foreignness(fb_info)) 1576 if (fb_check_foreignness(fb_info))
1557 return -ENOSYS; 1577 return -ENOSYS;
1558 1578
1559 remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, 1579 do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
1560 fb_is_primary_device(fb_info)); 1580 fb_is_primary_device(fb_info));
1561 1581
1582 if (num_registered_fb == FB_MAX)
1583 return -ENXIO;
1584
1562 num_registered_fb++; 1585 num_registered_fb++;
1563 for (i = 0 ; i < FB_MAX; i++) 1586 for (i = 0 ; i < FB_MAX; i++)
1564 if (!registered_fb[i]) 1587 if (!registered_fb[i])
1565 break; 1588 break;
1566 fb_info->node = i; 1589 fb_info->node = i;
1590 atomic_set(&fb_info->count, 1);
1567 mutex_init(&fb_info->lock); 1591 mutex_init(&fb_info->lock);
1568 mutex_init(&fb_info->mm_lock); 1592 mutex_init(&fb_info->mm_lock);
1569 1593
@@ -1609,36 +1633,14 @@ register_framebuffer(struct fb_info *fb_info)
1609 return 0; 1633 return 0;
1610} 1634}
1611 1635
1612 1636static int do_unregister_framebuffer(struct fb_info *fb_info)
1613/**
1614 * unregister_framebuffer - releases a frame buffer device
1615 * @fb_info: frame buffer info structure
1616 *
1617 * Unregisters a frame buffer device @fb_info.
1618 *
1619 * Returns negative errno on error, or zero for success.
1620 *
1621 * This function will also notify the framebuffer console
1622 * to release the driver.
1623 *
1624 * This is meant to be called within a driver's module_exit()
1625 * function. If this is called outside module_exit(), ensure
1626 * that the driver implements fb_open() and fb_release() to
1627 * check that no processes are using the device.
1628 */
1629
1630int
1631unregister_framebuffer(struct fb_info *fb_info)
1632{ 1637{
1633 struct fb_event event; 1638 struct fb_event event;
1634 int i, ret = 0; 1639 int i, ret = 0;
1635 1640
1636 i = fb_info->node; 1641 i = fb_info->node;
1637 if (!registered_fb[i]) { 1642 if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1638 ret = -EINVAL; 1643 return -EINVAL;
1639 goto done;
1640 }
1641
1642 1644
1643 if (!lock_fb_info(fb_info)) 1645 if (!lock_fb_info(fb_info))
1644 return -ENODEV; 1646 return -ENODEV;
@@ -1646,16 +1648,14 @@ unregister_framebuffer(struct fb_info *fb_info)
1646 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); 1648 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1647 unlock_fb_info(fb_info); 1649 unlock_fb_info(fb_info);
1648 1650
1649 if (ret) { 1651 if (ret)
1650 ret = -EINVAL; 1652 return -EINVAL;
1651 goto done;
1652 }
1653 1653
1654 if (fb_info->pixmap.addr && 1654 if (fb_info->pixmap.addr &&
1655 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) 1655 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
1656 kfree(fb_info->pixmap.addr); 1656 kfree(fb_info->pixmap.addr);
1657 fb_destroy_modelist(&fb_info->modelist); 1657 fb_destroy_modelist(&fb_info->modelist);
1658 registered_fb[i]=NULL; 1658 registered_fb[i] = NULL;
1659 num_registered_fb--; 1659 num_registered_fb--;
1660 fb_cleanup_device(fb_info); 1660 fb_cleanup_device(fb_info);
1661 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1661 device_destroy(fb_class, MKDEV(FB_MAJOR, i));
@@ -1663,9 +1663,65 @@ unregister_framebuffer(struct fb_info *fb_info)
1663 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1663 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1664 1664
1665 /* this may free fb info */ 1665 /* this may free fb info */
1666 if (fb_info->fbops->fb_destroy) 1666 put_fb_info(fb_info);
1667 fb_info->fbops->fb_destroy(fb_info); 1667 return 0;
1668done: 1668}
1669
1670void remove_conflicting_framebuffers(struct apertures_struct *a,
1671 const char *name, bool primary)
1672{
1673 mutex_lock(&registration_lock);
1674 do_remove_conflicting_framebuffers(a, name, primary);
1675 mutex_unlock(&registration_lock);
1676}
1677EXPORT_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 */
1688int
1689register_framebuffer(struct fb_info *fb_info)
1690{
1691 int ret;
1692
1693 mutex_lock(&registration_lock);
1694 ret = do_register_framebuffer(fb_info);
1695 mutex_unlock(&registration_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 */
1716int
1717unregister_framebuffer(struct fb_info *fb_info)
1718{
1719 int ret;
1720
1721 mutex_lock(&registration_lock);
1722 ret = do_unregister_framebuffer(fb_info);
1723 mutex_unlock(&registration_lock);
1724
1669 return ret; 1725 return ret;
1670} 1726}
1671 1727