diff options
Diffstat (limited to 'lib/vsprintf.c')
| -rw-r--r-- | lib/vsprintf.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 9f37d6208e99..86c3385b9eb3 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/dcache.h> | 31 | #include <linux/dcache.h> |
| 32 | #include <linux/cred.h> | 32 | #include <linux/cred.h> |
| 33 | #include <linux/uuid.h> | 33 | #include <linux/uuid.h> |
| 34 | #include <linux/of.h> | ||
| 34 | #include <net/addrconf.h> | 35 | #include <net/addrconf.h> |
| 35 | #ifdef CONFIG_BLOCK | 36 | #ifdef CONFIG_BLOCK |
| 36 | #include <linux/blkdev.h> | 37 | #include <linux/blkdev.h> |
| @@ -1470,6 +1471,126 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt) | |||
| 1470 | return format_flags(buf, end, flags, names); | 1471 | return format_flags(buf, end, flags, names); |
| 1471 | } | 1472 | } |
| 1472 | 1473 | ||
| 1474 | static const char *device_node_name_for_depth(const struct device_node *np, int depth) | ||
| 1475 | { | ||
| 1476 | for ( ; np && depth; depth--) | ||
| 1477 | np = np->parent; | ||
| 1478 | |||
| 1479 | return kbasename(np->full_name); | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | static noinline_for_stack | ||
| 1483 | char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end) | ||
| 1484 | { | ||
| 1485 | int depth; | ||
| 1486 | const struct device_node *parent = np->parent; | ||
| 1487 | static const struct printf_spec strspec = { | ||
| 1488 | .field_width = -1, | ||
| 1489 | .precision = -1, | ||
| 1490 | }; | ||
| 1491 | |||
| 1492 | /* special case for root node */ | ||
| 1493 | if (!parent) | ||
| 1494 | return string(buf, end, "/", strspec); | ||
| 1495 | |||
| 1496 | for (depth = 0; parent->parent; depth++) | ||
| 1497 | parent = parent->parent; | ||
| 1498 | |||
| 1499 | for ( ; depth >= 0; depth--) { | ||
| 1500 | buf = string(buf, end, "/", strspec); | ||
| 1501 | buf = string(buf, end, device_node_name_for_depth(np, depth), | ||
| 1502 | strspec); | ||
| 1503 | } | ||
| 1504 | return buf; | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | static noinline_for_stack | ||
| 1508 | char *device_node_string(char *buf, char *end, struct device_node *dn, | ||
| 1509 | struct printf_spec spec, const char *fmt) | ||
| 1510 | { | ||
| 1511 | char tbuf[sizeof("xxxx") + 1]; | ||
| 1512 | const char *p; | ||
| 1513 | int ret; | ||
| 1514 | char *buf_start = buf; | ||
| 1515 | struct property *prop; | ||
| 1516 | bool has_mult, pass; | ||
| 1517 | static const struct printf_spec num_spec = { | ||
| 1518 | .flags = SMALL, | ||
| 1519 | .field_width = -1, | ||
| 1520 | .precision = -1, | ||
| 1521 | .base = 10, | ||
| 1522 | }; | ||
| 1523 | |||
| 1524 | struct printf_spec str_spec = spec; | ||
| 1525 | str_spec.field_width = -1; | ||
| 1526 | |||
| 1527 | if (!IS_ENABLED(CONFIG_OF)) | ||
| 1528 | return string(buf, end, "(!OF)", spec); | ||
| 1529 | |||
| 1530 | if ((unsigned long)dn < PAGE_SIZE) | ||
| 1531 | return string(buf, end, "(null)", spec); | ||
| 1532 | |||
| 1533 | /* simple case without anything any more format specifiers */ | ||
| 1534 | fmt++; | ||
| 1535 | if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0) | ||
| 1536 | fmt = "f"; | ||
| 1537 | |||
| 1538 | for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) { | ||
| 1539 | if (pass) { | ||
| 1540 | if (buf < end) | ||
| 1541 | *buf = ':'; | ||
| 1542 | buf++; | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | switch (*fmt) { | ||
| 1546 | case 'f': /* full_name */ | ||
| 1547 | buf = device_node_gen_full_name(dn, buf, end); | ||
| 1548 | break; | ||
| 1549 | case 'n': /* name */ | ||
| 1550 | buf = string(buf, end, dn->name, str_spec); | ||
| 1551 | break; | ||
| 1552 | case 'p': /* phandle */ | ||
| 1553 | buf = number(buf, end, (unsigned int)dn->phandle, num_spec); | ||
| 1554 | break; | ||
| 1555 | case 'P': /* path-spec */ | ||
| 1556 | p = kbasename(of_node_full_name(dn)); | ||
| 1557 | if (!p[1]) | ||
| 1558 | p = "/"; | ||
| 1559 | buf = string(buf, end, p, str_spec); | ||
| 1560 | break; | ||
| 1561 | case 'F': /* flags */ | ||
| 1562 | tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-'; | ||
| 1563 | tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-'; | ||
| 1564 | tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-'; | ||
| 1565 | tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-'; | ||
| 1566 | tbuf[4] = 0; | ||
| 1567 | buf = string(buf, end, tbuf, str_spec); | ||
| 1568 | break; | ||
| 1569 | case 'c': /* major compatible string */ | ||
| 1570 | ret = of_property_read_string(dn, "compatible", &p); | ||
| 1571 | if (!ret) | ||
| 1572 | buf = string(buf, end, p, str_spec); | ||
| 1573 | break; | ||
| 1574 | case 'C': /* full compatible string */ | ||
| 1575 | has_mult = false; | ||
| 1576 | of_property_for_each_string(dn, "compatible", prop, p) { | ||
| 1577 | if (has_mult) | ||
| 1578 | buf = string(buf, end, ",", str_spec); | ||
| 1579 | buf = string(buf, end, "\"", str_spec); | ||
| 1580 | buf = string(buf, end, p, str_spec); | ||
| 1581 | buf = string(buf, end, "\"", str_spec); | ||
| 1582 | |||
| 1583 | has_mult = true; | ||
| 1584 | } | ||
| 1585 | break; | ||
| 1586 | default: | ||
| 1587 | break; | ||
| 1588 | } | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | return widen_string(buf, buf - buf_start, end, spec); | ||
| 1592 | } | ||
| 1593 | |||
| 1473 | int kptr_restrict __read_mostly; | 1594 | int kptr_restrict __read_mostly; |
| 1474 | 1595 | ||
| 1475 | /* | 1596 | /* |
| @@ -1566,6 +1687,16 @@ int kptr_restrict __read_mostly; | |||
| 1566 | * p page flags (see struct page) given as pointer to unsigned long | 1687 | * p page flags (see struct page) given as pointer to unsigned long |
| 1567 | * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t | 1688 | * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t |
| 1568 | * v vma flags (VM_*) given as pointer to unsigned long | 1689 | * v vma flags (VM_*) given as pointer to unsigned long |
| 1690 | * - 'O' For a kobject based struct. Must be one of the following: | ||
| 1691 | * - 'OF[fnpPcCF]' For a device tree object | ||
| 1692 | * Without any optional arguments prints the full_name | ||
| 1693 | * f device node full_name | ||
| 1694 | * n device node name | ||
| 1695 | * p device node phandle | ||
| 1696 | * P device node path spec (name + @unit) | ||
| 1697 | * F device node flags | ||
| 1698 | * c major compatible string | ||
| 1699 | * C full compatible string | ||
| 1569 | * | 1700 | * |
| 1570 | * ** Please update also Documentation/printk-formats.txt when making changes ** | 1701 | * ** Please update also Documentation/printk-formats.txt when making changes ** |
| 1571 | * | 1702 | * |
| @@ -1721,6 +1852,11 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
| 1721 | 1852 | ||
| 1722 | case 'G': | 1853 | case 'G': |
| 1723 | return flags_string(buf, end, ptr, fmt); | 1854 | return flags_string(buf, end, ptr, fmt); |
| 1855 | case 'O': | ||
| 1856 | switch (fmt[1]) { | ||
| 1857 | case 'F': | ||
| 1858 | return device_node_string(buf, end, ptr, spec, fmt + 1); | ||
| 1859 | } | ||
| 1724 | } | 1860 | } |
| 1725 | spec.flags |= SMALL; | 1861 | spec.flags |= SMALL; |
| 1726 | if (spec.field_width == -1) { | 1862 | if (spec.field_width == -1) { |
