aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/via/viafbdev.c
diff options
context:
space:
mode:
authorFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2010-09-04 21:33:28 -0400
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2010-09-23 22:14:59 -0400
commit2a9183923af1f6f4da66aeabf9fa5af0dc58ccec (patch)
tree710f8f8fc1b5f922e4c6405abf60eedaff5eb715 /drivers/video/via/viafbdev.c
parentcd7e9103e983ff0f518ac0e85cee265027ccbfa4 (diff)
viafb: add interface for output device configuration
This patch extends the proc entry to contain a possibility to view and change the output devices for each IGA. This is useful for debugging output problems as it provides a reliable way to query which low level devices are active after VIAs output device configuration nightmare happended. It's as well suitable for daily use as one can change the output configuration on the fly for example to connect a projector. At the moment it's still unstable. The reason is that we have to handle a bunch of undocumented output devices (those without a proper name) and that this patch is the first step to collect and verify the needed information. Basically the only configuration change that is expected to work at the moment is switching output devices between IGA1 and IGA2. Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Acked-by: Jonathan Corbet <corbet@lwn.net> Cc: Joseph Chan <JosephChan@via.com.tw> Cc: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'drivers/video/via/viafbdev.c')
-rw-r--r--drivers/video/via/viafbdev.c175
1 files changed, 151 insertions, 24 deletions
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 5a947b09626..80ce43a318b 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1431,38 +1431,169 @@ static const struct file_operations viafb_vt1636_proc_fops = {
1431 .write = viafb_vt1636_proc_write, 1431 .write = viafb_vt1636_proc_write,
1432}; 1432};
1433 1433
1434static void viafb_init_proc(struct proc_dir_entry **viafb_entry) 1434#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
1435
1436static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev)
1435{ 1437{
1436 *viafb_entry = proc_mkdir("viafb", NULL); 1438 char buf[64], *ptr = buf;
1437 if (*viafb_entry) { 1439 u32 devices;
1438 proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); 1440 bool add, sub;
1439 proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); 1441
1440 proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); 1442 if (count < 1 || count > 63)
1441 proc_create("dfpl", 0, *viafb_entry, &viafb_dfpl_proc_fops); 1443 return -EINVAL;
1442 if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info. 1444 if (copy_from_user(&buf[0], buffer, count))
1443 lvds_chip_name || VT1636_LVDS == 1445 return -EFAULT;
1444 viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { 1446 buf[count] = '\0';
1445 proc_create("vt1636", 0, *viafb_entry, &viafb_vt1636_proc_fops); 1447 add = buf[0] == '+';
1446 } 1448 sub = buf[0] == '-';
1449 if (add || sub)
1450 ptr++;
1451 devices = via_parse_odev(ptr, &ptr);
1452 if (*ptr == '\n')
1453 ptr++;
1454 if (*ptr != 0)
1455 return -EINVAL;
1456 if (add)
1457 *odev |= devices;
1458 else if (sub)
1459 *odev &= ~devices;
1460 else
1461 *odev = devices;
1462 return count;
1463}
1464
1465static int viafb_iga1_odev_proc_show(struct seq_file *m, void *v)
1466{
1467 via_odev_to_seq(m, viaparinfo->shared->iga1_devices);
1468 return 0;
1469}
1470
1471static int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file)
1472{
1473 return single_open(file, viafb_iga1_odev_proc_show, NULL);
1474}
1475
1476static ssize_t viafb_iga1_odev_proc_write(struct file *file,
1477 const char __user *buffer, size_t count, loff_t *pos)
1478{
1479 u32 dev_on, dev_off, dev_old, dev_new;
1480 ssize_t res;
1481
1482 dev_old = dev_new = viaparinfo->shared->iga1_devices;
1483 res = odev_update(buffer, count, &dev_new);
1484 if (res != count)
1485 return res;
1486 dev_off = dev_old & ~dev_new;
1487 dev_on = dev_new & ~dev_old;
1488 viaparinfo->shared->iga1_devices = dev_new;
1489 viaparinfo->shared->iga2_devices &= ~dev_new;
1490 via_set_source(dev_new, IGA1);
1491 return res;
1492}
1493
1494static const struct file_operations viafb_iga1_odev_proc_fops = {
1495 .owner = THIS_MODULE,
1496 .open = viafb_iga1_odev_proc_open,
1497 .read = seq_read,
1498 .llseek = seq_lseek,
1499 .release = single_release,
1500 .write = viafb_iga1_odev_proc_write,
1501};
1502
1503static int viafb_iga2_odev_proc_show(struct seq_file *m, void *v)
1504{
1505 via_odev_to_seq(m, viaparinfo->shared->iga2_devices);
1506 return 0;
1507}
1508
1509static int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file)
1510{
1511 return single_open(file, viafb_iga2_odev_proc_show, NULL);
1512}
1513
1514static ssize_t viafb_iga2_odev_proc_write(struct file *file,
1515 const char __user *buffer, size_t count, loff_t *pos)
1516{
1517 u32 dev_on, dev_off, dev_old, dev_new;
1518 ssize_t res;
1519
1520 dev_old = dev_new = viaparinfo->shared->iga2_devices;
1521 res = odev_update(buffer, count, &dev_new);
1522 if (res != count)
1523 return res;
1524 dev_off = dev_old & ~dev_new;
1525 dev_on = dev_new & ~dev_old;
1526 viaparinfo->shared->iga2_devices = dev_new;
1527 viaparinfo->shared->iga1_devices &= ~dev_new;
1528 via_set_source(dev_new, IGA2);
1529 return res;
1530}
1531
1532static const struct file_operations viafb_iga2_odev_proc_fops = {
1533 .owner = THIS_MODULE,
1534 .open = viafb_iga2_odev_proc_open,
1535 .read = seq_read,
1536 .llseek = seq_lseek,
1537 .release = single_release,
1538 .write = viafb_iga2_odev_proc_write,
1539};
1540
1541#define IS_VT1636(lvds_chip) ((lvds_chip).lvds_chip_name == VT1636_LVDS)
1542static void viafb_init_proc(struct viafb_shared *shared)
1543{
1544 struct proc_dir_entry *iga1_entry, *iga2_entry,
1545 *viafb_entry = proc_mkdir("viafb", NULL);
1546
1547 shared->proc_entry = viafb_entry;
1548 if (viafb_entry) {
1549#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
1550 proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_fops);
1551 proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_fops);
1552 proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_fops);
1553 proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_fops);
1554 if (IS_VT1636(shared->chip_info.lvds_chip_info)
1555 || IS_VT1636(shared->chip_info.lvds_chip_info2))
1556 proc_create("vt1636", 0, viafb_entry,
1557 &viafb_vt1636_proc_fops);
1558#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
1447 1559
1560 iga1_entry = proc_mkdir("iga1", viafb_entry);
1561 shared->iga1_proc_entry = iga1_entry;
1562 proc_create("output_devices", 0, iga1_entry,
1563 &viafb_iga1_odev_proc_fops);
1564 iga2_entry = proc_mkdir("iga2", viafb_entry);
1565 shared->iga2_proc_entry = iga2_entry;
1566 proc_create("output_devices", 0, iga2_entry,
1567 &viafb_iga2_odev_proc_fops);
1448 } 1568 }
1449} 1569}
1450static void viafb_remove_proc(struct proc_dir_entry *viafb_entry) 1570static void viafb_remove_proc(struct viafb_shared *shared)
1451{ 1571{
1452 struct chip_information *chip_info = &viaparinfo->shared->chip_info; 1572 struct proc_dir_entry *viafb_entry = shared->proc_entry,
1573 *iga1_entry = shared->iga1_proc_entry,
1574 *iga2_entry = shared->iga2_proc_entry;
1453 1575
1576 if (!viafb_entry)
1577 return;
1578
1579 remove_proc_entry("output_devices", iga2_entry);
1580 remove_proc_entry("iga2", viafb_entry);
1581 remove_proc_entry("output_devices", iga1_entry);
1582 remove_proc_entry("iga1", viafb_entry);
1583
1584#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
1454 remove_proc_entry("dvp0", viafb_entry);/* parent dir */ 1585 remove_proc_entry("dvp0", viafb_entry);/* parent dir */
1455 remove_proc_entry("dvp1", viafb_entry); 1586 remove_proc_entry("dvp1", viafb_entry);
1456 remove_proc_entry("dfph", viafb_entry); 1587 remove_proc_entry("dfph", viafb_entry);
1457 remove_proc_entry("dfpl", viafb_entry); 1588 remove_proc_entry("dfpl", viafb_entry);
1458 if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS 1589 if (IS_VT1636(shared->chip_info.lvds_chip_info)
1459 || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS) 1590 || IS_VT1636(shared->chip_info.lvds_chip_info2))
1460 remove_proc_entry("vt1636", viafb_entry); 1591 remove_proc_entry("vt1636", viafb_entry);
1592#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
1461 1593
1462 remove_proc_entry("viafb", NULL); 1594 remove_proc_entry("viafb", NULL);
1463} 1595}
1464 1596#undef IS_VT1636
1465#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
1466 1597
1467static int parse_mode(const char *str, u32 *xres, u32 *yres) 1598static int parse_mode(const char *str, u32 *xres, u32 *yres)
1468{ 1599{
@@ -1671,9 +1802,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
1671 viafbinfo->node, viafbinfo->fix.id, default_var.xres, 1802 viafbinfo->node, viafbinfo->fix.id, default_var.xres,
1672 default_var.yres, default_var.bits_per_pixel); 1803 default_var.yres, default_var.bits_per_pixel);
1673 1804
1674#ifdef CONFIG_FB_VIA_DIRECT_PROCFS 1805 viafb_init_proc(viaparinfo->shared);
1675 viafb_init_proc(&viaparinfo->shared->proc_entry);
1676#endif
1677 viafb_init_dac(IGA2); 1806 viafb_init_dac(IGA2);
1678 return 0; 1807 return 0;
1679 1808
@@ -1700,9 +1829,7 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev)
1700 unregister_framebuffer(viafbinfo); 1829 unregister_framebuffer(viafbinfo);
1701 if (viafb_dual_fb) 1830 if (viafb_dual_fb)
1702 unregister_framebuffer(viafbinfo1); 1831 unregister_framebuffer(viafbinfo1);
1703#ifdef CONFIG_FB_VIA_DIRECT_PROCFS 1832 viafb_remove_proc(viaparinfo->shared);
1704 viafb_remove_proc(viaparinfo->shared->proc_entry);
1705#endif
1706 framebuffer_release(viafbinfo); 1833 framebuffer_release(viafbinfo);
1707 if (viafb_dual_fb) 1834 if (viafb_dual_fb)
1708 framebuffer_release(viafbinfo1); 1835 framebuffer_release(viafbinfo1);