aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-12 13:42:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-12 13:42:36 -0400
commitdf43938bc581f831b80b14ae249078e8da3d6ef5 (patch)
tree544a9ae62e208a70cca56b5e3cb724b798eec681 /drivers/video
parent49f019c188aa1e0ed5c8cffbcc5533dfb0e732dd (diff)
parentc47747fde931c02455683bd00ea43eaa62f35b0e (diff)
Merge branch 'fbmem'
* fbmem: fbmem: make read/write/ioctl use the frame buffer at open time fbcon: add lifetime refcount to opened frame buffers
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbmem.c106
1 files changed, 80 insertions, 26 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index e0c2284924b6..ea16e654a9b6 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,13 +717,30 @@ 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];
733
734 if (info != file->private_data)
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);
700 u8 *buffer, *dst; 744 u8 *buffer, *dst;
701 u8 __iomem *src; 745 u8 __iomem *src;
702 int c, cnt = 0, err = 0; 746 int c, cnt = 0, err = 0;
@@ -761,9 +805,7 @@ static ssize_t
761fb_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)
762{ 806{
763 unsigned long p = *ppos; 807 unsigned long p = *ppos;
764 struct inode *inode = file->f_path.dentry->d_inode; 808 struct fb_info *info = file_fb_info(file);
765 int fbidx = iminor(inode);
766 struct fb_info *info = registered_fb[fbidx];
767 u8 *buffer, *src; 809 u8 *buffer, *src;
768 u8 __iomem *dst; 810 u8 __iomem *dst;
769 int c, cnt = 0, err = 0; 811 int c, cnt = 0, err = 0;
@@ -1141,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1141 1183
1142static 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)
1143{ 1185{
1144 struct inode *inode = file->f_path.dentry->d_inode; 1186 struct fb_info *info = file_fb_info(file);
1145 int fbidx = iminor(inode);
1146 struct fb_info *info = registered_fb[fbidx];
1147 1187
1188 if (!info)
1189 return -ENODEV;
1148 return do_fb_ioctl(info, cmd, arg); 1190 return do_fb_ioctl(info, cmd, arg);
1149} 1191}
1150 1192
@@ -1265,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
1265static long fb_compat_ioctl(struct file *file, unsigned int cmd, 1307static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1266 unsigned long arg) 1308 unsigned long arg)
1267{ 1309{
1268 struct inode *inode = file->f_path.dentry->d_inode; 1310 struct fb_info *info = file_fb_info(file);
1269 int fbidx = iminor(inode); 1311 struct fb_ops *fb;
1270 struct fb_info *info = registered_fb[fbidx];
1271 struct fb_ops *fb = info->fbops;
1272 long ret = -ENOIOCTLCMD; 1312 long ret = -ENOIOCTLCMD;
1273 1313
1314 if (!info)
1315 return -ENODEV;
1316 fb = info->fbops;
1274 switch(cmd) { 1317 switch(cmd) {
1275 case FBIOGET_VSCREENINFO: 1318 case FBIOGET_VSCREENINFO:
1276 case FBIOPUT_VSCREENINFO: 1319 case FBIOPUT_VSCREENINFO:
@@ -1303,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1303static int 1346static int
1304fb_mmap(struct file *file, struct vm_area_struct * vma) 1347fb_mmap(struct file *file, struct vm_area_struct * vma)
1305{ 1348{
1306 int fbidx = iminor(file->f_path.dentry->d_inode); 1349 struct fb_info *info = file_fb_info(file);
1307 struct fb_info *info = registered_fb[fbidx]; 1350 struct fb_ops *fb;
1308 struct fb_ops *fb = info->fbops;
1309 unsigned long off; 1351 unsigned long off;
1310 unsigned long start; 1352 unsigned long start;
1311 u32 len; 1353 u32 len;
1312 1354
1355 if (!info)
1356 return -ENODEV;
1313 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1357 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1314 return -EINVAL; 1358 return -EINVAL;
1315 off = vma->vm_pgoff << PAGE_SHIFT; 1359 off = vma->vm_pgoff << PAGE_SHIFT;
1360 fb = info->fbops;
1316 if (!fb) 1361 if (!fb)
1317 return -ENODEV; 1362 return -ENODEV;
1318 mutex_lock(&info->mm_lock); 1363 mutex_lock(&info->mm_lock);
@@ -1361,14 +1406,16 @@ __releases(&info->lock)
1361 struct fb_info *info; 1406 struct fb_info *info;
1362 int res = 0; 1407 int res = 0;
1363 1408
1364 if (fbidx >= FB_MAX) 1409 info = get_fb_info(fbidx);
1365 return -ENODEV; 1410 if (!info) {
1366 info = registered_fb[fbidx];
1367 if (!info)
1368 request_module("fb%d", fbidx); 1411 request_module("fb%d", fbidx);
1369 info = registered_fb[fbidx]; 1412 info = get_fb_info(fbidx);
1370 if (!info) 1413 if (!info)
1371 return -ENODEV; 1414 return -ENODEV;
1415 }
1416 if (IS_ERR(info))
1417 return PTR_ERR(info);
1418
1372 mutex_lock(&info->lock); 1419 mutex_lock(&info->lock);
1373 if (!try_module_get(info->fbops->owner)) { 1420 if (!try_module_get(info->fbops->owner)) {
1374 res = -ENODEV; 1421 res = -ENODEV;
@@ -1386,6 +1433,8 @@ __releases(&info->lock)
1386#endif 1433#endif
1387out: 1434out:
1388 mutex_unlock(&info->lock); 1435 mutex_unlock(&info->lock);
1436 if (res)
1437 put_fb_info(info);
1389 return res; 1438 return res;
1390} 1439}
1391 1440
@@ -1401,6 +1450,7 @@ __releases(&info->lock)
1401 info->fbops->fb_release(info,1); 1450 info->fbops->fb_release(info,1);
1402 module_put(info->fbops->owner); 1451 module_put(info->fbops->owner);
1403 mutex_unlock(&info->lock); 1452 mutex_unlock(&info->lock);
1453 put_fb_info(info);
1404 return 0; 1454 return 0;
1405} 1455}
1406 1456
@@ -1542,11 +1592,13 @@ register_framebuffer(struct fb_info *fb_info)
1542 remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, 1592 remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
1543 fb_is_primary_device(fb_info)); 1593 fb_is_primary_device(fb_info));
1544 1594
1595 mutex_lock(&registration_lock);
1545 num_registered_fb++; 1596 num_registered_fb++;
1546 for (i = 0 ; i < FB_MAX; i++) 1597 for (i = 0 ; i < FB_MAX; i++)
1547 if (!registered_fb[i]) 1598 if (!registered_fb[i])
1548 break; 1599 break;
1549 fb_info->node = i; 1600 fb_info->node = i;
1601 atomic_set(&fb_info->count, 1);
1550 mutex_init(&fb_info->lock); 1602 mutex_init(&fb_info->lock);
1551 mutex_init(&fb_info->mm_lock); 1603 mutex_init(&fb_info->mm_lock);
1552 1604
@@ -1583,6 +1635,7 @@ register_framebuffer(struct fb_info *fb_info)
1583 fb_var_to_videomode(&mode, &fb_info->var); 1635 fb_var_to_videomode(&mode, &fb_info->var);
1584 fb_add_videomode(&mode, &fb_info->modelist); 1636 fb_add_videomode(&mode, &fb_info->modelist);
1585 registered_fb[i] = fb_info; 1637 registered_fb[i] = fb_info;
1638 mutex_unlock(&registration_lock);
1586 1639
1587 event.info = fb_info; 1640 event.info = fb_info;
1588 if (!lock_fb_info(fb_info)) 1641 if (!lock_fb_info(fb_info))
@@ -1616,6 +1669,7 @@ unregister_framebuffer(struct fb_info *fb_info)
1616 struct fb_event event; 1669 struct fb_event event;
1617 int i, ret = 0; 1670 int i, ret = 0;
1618 1671
1672 mutex_lock(&registration_lock);
1619 i = fb_info->node; 1673 i = fb_info->node;
1620 if (!registered_fb[i]) { 1674 if (!registered_fb[i]) {
1621 ret = -EINVAL; 1675 ret = -EINVAL;
@@ -1638,7 +1692,7 @@ unregister_framebuffer(struct fb_info *fb_info)
1638 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) 1692 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
1639 kfree(fb_info->pixmap.addr); 1693 kfree(fb_info->pixmap.addr);
1640 fb_destroy_modelist(&fb_info->modelist); 1694 fb_destroy_modelist(&fb_info->modelist);
1641 registered_fb[i]=NULL; 1695 registered_fb[i] = NULL;
1642 num_registered_fb--; 1696 num_registered_fb--;
1643 fb_cleanup_device(fb_info); 1697 fb_cleanup_device(fb_info);
1644 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1698 device_destroy(fb_class, MKDEV(FB_MAJOR, i));
@@ -1646,9 +1700,9 @@ unregister_framebuffer(struct fb_info *fb_info)
1646 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1700 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1647 1701
1648 /* this may free fb info */ 1702 /* this may free fb info */
1649 if (fb_info->fbops->fb_destroy) 1703 put_fb_info(fb_info);
1650 fb_info->fbops->fb_destroy(fb_info);
1651done: 1704done:
1705 mutex_unlock(&registration_lock);
1652 return ret; 1706 return ret;
1653} 1707}
1654 1708