30
30
* authorization from the copyright holder(s) and author(s).
31
31
*/
32
32
33
+ #include <linux/ctype.h>
33
34
#include <linux/list.h>
34
35
#include <linux/list_sort.h>
35
36
#include <linux/export.h>
@@ -1408,6 +1409,151 @@ void drm_connector_list_update(struct drm_connector *connector)
1408
1409
}
1409
1410
EXPORT_SYMBOL (drm_connector_list_update );
1410
1411
1412
+ static int drm_mode_parse_cmdline_bpp (const char * str , char * * end_ptr ,
1413
+ struct drm_cmdline_mode * mode )
1414
+ {
1415
+ unsigned int bpp ;
1416
+
1417
+ if (str [0 ] != '-' )
1418
+ return - EINVAL ;
1419
+
1420
+ str ++ ;
1421
+ bpp = simple_strtol (str , end_ptr , 10 );
1422
+ if (* end_ptr == str )
1423
+ return - EINVAL ;
1424
+
1425
+ mode -> bpp = bpp ;
1426
+ mode -> bpp_specified = true;
1427
+
1428
+ return 0 ;
1429
+ }
1430
+
1431
+ static int drm_mode_parse_cmdline_refresh (const char * str , char * * end_ptr ,
1432
+ struct drm_cmdline_mode * mode )
1433
+ {
1434
+ unsigned int refresh ;
1435
+
1436
+ if (str [0 ] != '@' )
1437
+ return - EINVAL ;
1438
+
1439
+ str ++ ;
1440
+ refresh = simple_strtol (str , end_ptr , 10 );
1441
+ if (* end_ptr == str )
1442
+ return - EINVAL ;
1443
+
1444
+ mode -> refresh = refresh ;
1445
+ mode -> refresh_specified = true;
1446
+
1447
+ return 0 ;
1448
+ }
1449
+
1450
+ static int drm_mode_parse_cmdline_extra (const char * str , int length ,
1451
+ struct drm_connector * connector ,
1452
+ struct drm_cmdline_mode * mode )
1453
+ {
1454
+ int i ;
1455
+
1456
+ for (i = 0 ; i < length ; i ++ ) {
1457
+ switch (str [i ]) {
1458
+ case 'i' :
1459
+ mode -> interlace = true;
1460
+ break ;
1461
+ case 'm' :
1462
+ mode -> margins = true;
1463
+ break ;
1464
+ case 'D' :
1465
+ if (mode -> force != DRM_FORCE_UNSPECIFIED )
1466
+ return - EINVAL ;
1467
+
1468
+ if ((connector -> connector_type != DRM_MODE_CONNECTOR_DVII ) &&
1469
+ (connector -> connector_type != DRM_MODE_CONNECTOR_HDMIB ))
1470
+ mode -> force = DRM_FORCE_ON ;
1471
+ else
1472
+ mode -> force = DRM_FORCE_ON_DIGITAL ;
1473
+ break ;
1474
+ case 'd' :
1475
+ if (mode -> force != DRM_FORCE_UNSPECIFIED )
1476
+ return - EINVAL ;
1477
+
1478
+ mode -> force = DRM_FORCE_OFF ;
1479
+ break ;
1480
+ case 'e' :
1481
+ if (mode -> force != DRM_FORCE_UNSPECIFIED )
1482
+ return - EINVAL ;
1483
+
1484
+ mode -> force = DRM_FORCE_ON ;
1485
+ break ;
1486
+ default :
1487
+ return - EINVAL ;
1488
+ }
1489
+ }
1490
+
1491
+ return 0 ;
1492
+ }
1493
+
1494
+ static int drm_mode_parse_cmdline_res_mode (const char * str , unsigned int length ,
1495
+ bool extras ,
1496
+ struct drm_connector * connector ,
1497
+ struct drm_cmdline_mode * mode )
1498
+ {
1499
+ const char * str_start = str ;
1500
+ bool rb = false, cvt = false;
1501
+ int xres = 0 , yres = 0 ;
1502
+ int remaining , i ;
1503
+ char * end_ptr ;
1504
+
1505
+ xres = simple_strtol (str , & end_ptr , 10 );
1506
+ if (end_ptr == str )
1507
+ return - EINVAL ;
1508
+
1509
+ if (end_ptr [0 ] != 'x' )
1510
+ return - EINVAL ;
1511
+ end_ptr ++ ;
1512
+
1513
+ str = end_ptr ;
1514
+ yres = simple_strtol (str , & end_ptr , 10 );
1515
+ if (end_ptr == str )
1516
+ return - EINVAL ;
1517
+
1518
+ remaining = length - (end_ptr - str_start );
1519
+ if (remaining < 0 )
1520
+ return - EINVAL ;
1521
+
1522
+ for (i = 0 ; i < remaining ; i ++ ) {
1523
+ switch (end_ptr [i ]) {
1524
+ case 'M' :
1525
+ cvt = true;
1526
+ break ;
1527
+ case 'R' :
1528
+ rb = true;
1529
+ break ;
1530
+ default :
1531
+ /*
1532
+ * Try to pass that to our extras parsing
1533
+ * function to handle the case where the
1534
+ * extras are directly after the resolution
1535
+ */
1536
+ if (extras ) {
1537
+ int ret = drm_mode_parse_cmdline_extra (end_ptr + i ,
1538
+ 1 ,
1539
+ connector ,
1540
+ mode );
1541
+ if (ret )
1542
+ return ret ;
1543
+ } else {
1544
+ return - EINVAL ;
1545
+ }
1546
+ }
1547
+ }
1548
+
1549
+ mode -> xres = xres ;
1550
+ mode -> yres = yres ;
1551
+ mode -> cvt = cvt ;
1552
+ mode -> rb = rb ;
1553
+
1554
+ return 0 ;
1555
+ }
1556
+
1411
1557
/**
1412
1558
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector
1413
1559
* @mode_option: optional per connector mode option
@@ -1434,13 +1580,12 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1434
1580
struct drm_cmdline_mode * mode )
1435
1581
{
1436
1582
const char * name ;
1437
- unsigned int namelen ;
1438
- bool res_specified = false, bpp_specified = false, refresh_specified = false;
1439
- unsigned int xres = 0 , yres = 0 , bpp = 32 , refresh = 0 ;
1440
- bool yres_specified = false, cvt = false, rb = false;
1441
- bool interlace = false, margins = false, was_digit = false;
1442
- int i ;
1443
- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED ;
1583
+ bool parse_extras = false;
1584
+ unsigned int bpp_off = 0 , refresh_off = 0 ;
1585
+ unsigned int mode_end = 0 ;
1586
+ char * bpp_ptr = NULL , * refresh_ptr = NULL , * extra_ptr = NULL ;
1587
+ char * bpp_end_ptr = NULL , * refresh_end_ptr = NULL ;
1588
+ int ret ;
1444
1589
1445
1590
#ifdef CONFIG_FB
1446
1591
if (!mode_option )
@@ -1453,127 +1598,77 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1453
1598
}
1454
1599
1455
1600
name = mode_option ;
1456
- namelen = strlen (name );
1457
- for (i = namelen - 1 ; i >= 0 ; i -- ) {
1458
- switch (name [i ]) {
1459
- case '@' :
1460
- if (!refresh_specified && !bpp_specified &&
1461
- !yres_specified && !cvt && !rb && was_digit ) {
1462
- refresh = simple_strtol (& name [i + 1 ], NULL , 10 );
1463
- refresh_specified = true;
1464
- was_digit = false;
1465
- } else
1466
- goto done ;
1467
- break ;
1468
- case '-' :
1469
- if (!bpp_specified && !yres_specified && !cvt &&
1470
- !rb && was_digit ) {
1471
- bpp = simple_strtol (& name [i + 1 ], NULL , 10 );
1472
- bpp_specified = true;
1473
- was_digit = false;
1474
- } else
1475
- goto done ;
1476
- break ;
1477
- case 'x' :
1478
- if (!yres_specified && was_digit ) {
1479
- yres = simple_strtol (& name [i + 1 ], NULL , 10 );
1480
- yres_specified = true;
1481
- was_digit = false;
1482
- } else
1483
- goto done ;
1484
- break ;
1485
- case '0' ... '9' :
1486
- was_digit = true;
1487
- break ;
1488
- case 'M' :
1489
- if (yres_specified || cvt || was_digit )
1490
- goto done ;
1491
- cvt = true;
1492
- break ;
1493
- case 'R' :
1494
- if (yres_specified || cvt || rb || was_digit )
1495
- goto done ;
1496
- rb = true;
1497
- break ;
1498
- case 'm' :
1499
- if (cvt || yres_specified || was_digit )
1500
- goto done ;
1501
- margins = true;
1502
- break ;
1503
- case 'i' :
1504
- if (cvt || yres_specified || was_digit )
1505
- goto done ;
1506
- interlace = true;
1507
- break ;
1508
- case 'e' :
1509
- if (yres_specified || bpp_specified || refresh_specified ||
1510
- was_digit || (force != DRM_FORCE_UNSPECIFIED ))
1511
- goto done ;
1512
1601
1513
- force = DRM_FORCE_ON ;
1514
- break ;
1515
- case 'D' :
1516
- if (yres_specified || bpp_specified || refresh_specified ||
1517
- was_digit || (force != DRM_FORCE_UNSPECIFIED ))
1518
- goto done ;
1602
+ if (!isdigit (name [0 ]))
1603
+ return false;
1519
1604
1520
- if ((connector -> connector_type != DRM_MODE_CONNECTOR_DVII ) &&
1521
- (connector -> connector_type != DRM_MODE_CONNECTOR_HDMIB ))
1522
- force = DRM_FORCE_ON ;
1523
- else
1524
- force = DRM_FORCE_ON_DIGITAL ;
1525
- break ;
1526
- case 'd' :
1527
- if (yres_specified || bpp_specified || refresh_specified ||
1528
- was_digit || (force != DRM_FORCE_UNSPECIFIED ))
1529
- goto done ;
1605
+ /* Try to locate the bpp and refresh specifiers, if any */
1606
+ bpp_ptr = strchr (name , '-' );
1607
+ if (bpp_ptr ) {
1608
+ bpp_off = bpp_ptr - name ;
1609
+ mode -> bpp_specified = true;
1610
+ }
1530
1611
1531
- force = DRM_FORCE_OFF ;
1532
- break ;
1533
- default :
1534
- goto done ;
1535
- }
1612
+ refresh_ptr = strchr (name , '@' );
1613
+ if (refresh_ptr ) {
1614
+ refresh_off = refresh_ptr - name ;
1615
+ mode -> refresh_specified = true;
1536
1616
}
1537
1617
1538
- if ( i < 0 && yres_specified ) {
1539
- char * ch ;
1540
- xres = simple_strtol ( name , & ch , 10 );
1541
- if (( ch != NULL ) && ( * ch == 'x' ))
1542
- res_specified = true ;
1543
- else
1544
- i = ch - name ;
1545
- } else if (! yres_specified && was_digit ) {
1546
- /* catch mode that begins with digits but has no 'x' */
1547
- i = 0 ;
1618
+ /* Locate the end of the name / resolution, and parse it */
1619
+ if ( bpp_ptr && refresh_ptr ) {
1620
+ mode_end = min ( bpp_off , refresh_off );
1621
+ } else if ( bpp_ptr ) {
1622
+ mode_end = bpp_off ;
1623
+ } else if ( refresh_ptr ) {
1624
+ mode_end = refresh_off ;
1625
+ } else {
1626
+ mode_end = strlen ( name );
1627
+ parse_extras = true ;
1548
1628
}
1549
- done :
1550
- if (i >= 0 ) {
1551
- pr_warn ("[drm] parse error at position %i in video mode '%s'\n" ,
1552
- i , name );
1553
- mode -> specified = false;
1629
+
1630
+ ret = drm_mode_parse_cmdline_res_mode (name , mode_end ,
1631
+ parse_extras ,
1632
+ connector ,
1633
+ mode );
1634
+ if (ret )
1554
1635
return false;
1555
- }
1636
+ mode -> specified = true;
1556
1637
1557
- if (res_specified ) {
1558
- mode -> specified = true ;
1559
- mode -> xres = xres ;
1560
- mode -> yres = yres ;
1638
+ if (bpp_ptr ) {
1639
+ ret = drm_mode_parse_cmdline_bpp ( bpp_ptr , & bpp_end_ptr , mode ) ;
1640
+ if ( ret )
1641
+ return false ;
1561
1642
}
1562
1643
1563
- if (refresh_specified ) {
1564
- mode -> refresh_specified = true;
1565
- mode -> refresh = refresh ;
1644
+ if (refresh_ptr ) {
1645
+ ret = drm_mode_parse_cmdline_refresh (refresh_ptr ,
1646
+ & refresh_end_ptr , mode );
1647
+ if (ret )
1648
+ return false;
1566
1649
}
1567
1650
1568
- if (bpp_specified ) {
1569
- mode -> bpp_specified = true;
1570
- mode -> bpp = bpp ;
1651
+ /*
1652
+ * Locate the end of the bpp / refresh, and parse the extras
1653
+ * if relevant
1654
+ */
1655
+ if (bpp_ptr && refresh_ptr )
1656
+ extra_ptr = max (bpp_end_ptr , refresh_end_ptr );
1657
+ else if (bpp_ptr )
1658
+ extra_ptr = bpp_end_ptr ;
1659
+ else if (refresh_ptr )
1660
+ extra_ptr = refresh_end_ptr ;
1661
+
1662
+ if (extra_ptr ) {
1663
+ int remaining = strlen (name ) - (extra_ptr - name );
1664
+
1665
+ /*
1666
+ * We still have characters to process, while
1667
+ * we shouldn't have any
1668
+ */
1669
+ if (remaining > 0 )
1670
+ return false;
1571
1671
}
1572
- mode -> rb = rb ;
1573
- mode -> cvt = cvt ;
1574
- mode -> interlace = interlace ;
1575
- mode -> margins = margins ;
1576
- mode -> force = force ;
1577
1672
1578
1673
return true;
1579
1674
}
0 commit comments