18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * dice_proc.c - a part of driver for Dice based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) Clemens Ladisch 68c2ecf20Sopenharmony_ci * Copyright (c) 2014 Takashi Sakamoto 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "dice.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic int dice_proc_read_mem(struct snd_dice *dice, void *buffer, 128c2ecf20Sopenharmony_ci unsigned int offset_q, unsigned int quadlets) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci unsigned int i; 158c2ecf20Sopenharmony_ci int err; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, 188c2ecf20Sopenharmony_ci DICE_PRIVATE_SPACE + 4 * offset_q, 198c2ecf20Sopenharmony_ci buffer, 4 * quadlets, 0); 208c2ecf20Sopenharmony_ci if (err < 0) 218c2ecf20Sopenharmony_ci return err; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci for (i = 0; i < quadlets; ++i) 248c2ecf20Sopenharmony_ci be32_to_cpus(&((u32 *)buffer)[i]); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic const char *str_from_array(const char *const strs[], unsigned int count, 308c2ecf20Sopenharmony_ci unsigned int i) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci if (i < count) 338c2ecf20Sopenharmony_ci return strs[i]; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return "(unknown)"; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void dice_proc_fixup_string(char *s, unsigned int size) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci unsigned int i; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci for (i = 0; i < size; i += 4) 438c2ecf20Sopenharmony_ci cpu_to_le32s((u32 *)(s + i)); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci for (i = 0; i < size - 2; ++i) { 468c2ecf20Sopenharmony_ci if (s[i] == '\0') 478c2ecf20Sopenharmony_ci return; 488c2ecf20Sopenharmony_ci if (s[i] == '\\' && s[i + 1] == '\\') { 498c2ecf20Sopenharmony_ci s[i + 2] = '\0'; 508c2ecf20Sopenharmony_ci return; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci s[size - 1] = '\0'; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void dice_proc_read(struct snd_info_entry *entry, 578c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci static const char *const section_names[5] = { 608c2ecf20Sopenharmony_ci "global", "tx", "rx", "ext_sync", "unused2" 618c2ecf20Sopenharmony_ci }; 628c2ecf20Sopenharmony_ci static const char *const clock_sources[] = { 638c2ecf20Sopenharmony_ci "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif", 648c2ecf20Sopenharmony_ci "wc", "arx1", "arx2", "arx3", "arx4", "internal" 658c2ecf20Sopenharmony_ci }; 668c2ecf20Sopenharmony_ci static const char *const rates[] = { 678c2ecf20Sopenharmony_ci "32000", "44100", "48000", "88200", "96000", "176400", "192000", 688c2ecf20Sopenharmony_ci "any low", "any mid", "any high", "none" 698c2ecf20Sopenharmony_ci }; 708c2ecf20Sopenharmony_ci struct snd_dice *dice = entry->private_data; 718c2ecf20Sopenharmony_ci u32 sections[ARRAY_SIZE(section_names) * 2]; 728c2ecf20Sopenharmony_ci struct { 738c2ecf20Sopenharmony_ci u32 number; 748c2ecf20Sopenharmony_ci u32 size; 758c2ecf20Sopenharmony_ci } tx_rx_header; 768c2ecf20Sopenharmony_ci union { 778c2ecf20Sopenharmony_ci struct { 788c2ecf20Sopenharmony_ci u32 owner_hi, owner_lo; 798c2ecf20Sopenharmony_ci u32 notification; 808c2ecf20Sopenharmony_ci char nick_name[NICK_NAME_SIZE]; 818c2ecf20Sopenharmony_ci u32 clock_select; 828c2ecf20Sopenharmony_ci u32 enable; 838c2ecf20Sopenharmony_ci u32 status; 848c2ecf20Sopenharmony_ci u32 extended_status; 858c2ecf20Sopenharmony_ci u32 sample_rate; 868c2ecf20Sopenharmony_ci u32 version; 878c2ecf20Sopenharmony_ci u32 clock_caps; 888c2ecf20Sopenharmony_ci char clock_source_names[CLOCK_SOURCE_NAMES_SIZE]; 898c2ecf20Sopenharmony_ci } global; 908c2ecf20Sopenharmony_ci struct { 918c2ecf20Sopenharmony_ci u32 iso; 928c2ecf20Sopenharmony_ci u32 number_audio; 938c2ecf20Sopenharmony_ci u32 number_midi; 948c2ecf20Sopenharmony_ci u32 speed; 958c2ecf20Sopenharmony_ci char names[TX_NAMES_SIZE]; 968c2ecf20Sopenharmony_ci u32 ac3_caps; 978c2ecf20Sopenharmony_ci u32 ac3_enable; 988c2ecf20Sopenharmony_ci } tx; 998c2ecf20Sopenharmony_ci struct { 1008c2ecf20Sopenharmony_ci u32 iso; 1018c2ecf20Sopenharmony_ci u32 seq_start; 1028c2ecf20Sopenharmony_ci u32 number_audio; 1038c2ecf20Sopenharmony_ci u32 number_midi; 1048c2ecf20Sopenharmony_ci char names[RX_NAMES_SIZE]; 1058c2ecf20Sopenharmony_ci u32 ac3_caps; 1068c2ecf20Sopenharmony_ci u32 ac3_enable; 1078c2ecf20Sopenharmony_ci } rx; 1088c2ecf20Sopenharmony_ci struct { 1098c2ecf20Sopenharmony_ci u32 clock_source; 1108c2ecf20Sopenharmony_ci u32 locked; 1118c2ecf20Sopenharmony_ci u32 rate; 1128c2ecf20Sopenharmony_ci u32 adat_user_data; 1138c2ecf20Sopenharmony_ci } ext_sync; 1148c2ecf20Sopenharmony_ci } buf; 1158c2ecf20Sopenharmony_ci unsigned int quadlets, stream, i; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0) 1188c2ecf20Sopenharmony_ci return; 1198c2ecf20Sopenharmony_ci snd_iprintf(buffer, "sections:\n"); 1208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(section_names); ++i) 1218c2ecf20Sopenharmony_ci snd_iprintf(buffer, " %s: offset %u, size %u\n", 1228c2ecf20Sopenharmony_ci section_names[i], 1238c2ecf20Sopenharmony_ci sections[i * 2], sections[i * 2 + 1]); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4); 1268c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0) 1278c2ecf20Sopenharmony_ci return; 1288c2ecf20Sopenharmony_ci snd_iprintf(buffer, "global:\n"); 1298c2ecf20Sopenharmony_ci snd_iprintf(buffer, " owner: %04x:%04x%08x\n", 1308c2ecf20Sopenharmony_ci buf.global.owner_hi >> 16, 1318c2ecf20Sopenharmony_ci buf.global.owner_hi & 0xffff, buf.global.owner_lo); 1328c2ecf20Sopenharmony_ci snd_iprintf(buffer, " notification: %08x\n", buf.global.notification); 1338c2ecf20Sopenharmony_ci dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE); 1348c2ecf20Sopenharmony_ci snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name); 1358c2ecf20Sopenharmony_ci snd_iprintf(buffer, " clock select: %s %s\n", 1368c2ecf20Sopenharmony_ci str_from_array(clock_sources, ARRAY_SIZE(clock_sources), 1378c2ecf20Sopenharmony_ci buf.global.clock_select & CLOCK_SOURCE_MASK), 1388c2ecf20Sopenharmony_ci str_from_array(rates, ARRAY_SIZE(rates), 1398c2ecf20Sopenharmony_ci (buf.global.clock_select & CLOCK_RATE_MASK) 1408c2ecf20Sopenharmony_ci >> CLOCK_RATE_SHIFT)); 1418c2ecf20Sopenharmony_ci snd_iprintf(buffer, " enable: %u\n", buf.global.enable); 1428c2ecf20Sopenharmony_ci snd_iprintf(buffer, " status: %slocked %s\n", 1438c2ecf20Sopenharmony_ci buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un", 1448c2ecf20Sopenharmony_ci str_from_array(rates, ARRAY_SIZE(rates), 1458c2ecf20Sopenharmony_ci (buf.global.status & 1468c2ecf20Sopenharmony_ci STATUS_NOMINAL_RATE_MASK) 1478c2ecf20Sopenharmony_ci >> CLOCK_RATE_SHIFT)); 1488c2ecf20Sopenharmony_ci snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); 1498c2ecf20Sopenharmony_ci snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); 1508c2ecf20Sopenharmony_ci if (quadlets >= 90) { 1518c2ecf20Sopenharmony_ci snd_iprintf(buffer, " version: %u.%u.%u.%u\n", 1528c2ecf20Sopenharmony_ci (buf.global.version >> 24) & 0xff, 1538c2ecf20Sopenharmony_ci (buf.global.version >> 16) & 0xff, 1548c2ecf20Sopenharmony_ci (buf.global.version >> 8) & 0xff, 1558c2ecf20Sopenharmony_ci (buf.global.version >> 0) & 0xff); 1568c2ecf20Sopenharmony_ci snd_iprintf(buffer, " clock caps:"); 1578c2ecf20Sopenharmony_ci for (i = 0; i <= 6; ++i) 1588c2ecf20Sopenharmony_ci if (buf.global.clock_caps & (1 << i)) 1598c2ecf20Sopenharmony_ci snd_iprintf(buffer, " %s", rates[i]); 1608c2ecf20Sopenharmony_ci for (i = 0; i <= 12; ++i) 1618c2ecf20Sopenharmony_ci if (buf.global.clock_caps & (1 << (16 + i))) 1628c2ecf20Sopenharmony_ci snd_iprintf(buffer, " %s", clock_sources[i]); 1638c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 1648c2ecf20Sopenharmony_ci dice_proc_fixup_string(buf.global.clock_source_names, 1658c2ecf20Sopenharmony_ci CLOCK_SOURCE_NAMES_SIZE); 1668c2ecf20Sopenharmony_ci snd_iprintf(buffer, " clock source names: %s\n", 1678c2ecf20Sopenharmony_ci buf.global.clock_source_names); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0) 1718c2ecf20Sopenharmony_ci return; 1728c2ecf20Sopenharmony_ci quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4); 1738c2ecf20Sopenharmony_ci for (stream = 0; stream < tx_rx_header.number; ++stream) { 1748c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 + 1758c2ecf20Sopenharmony_ci stream * tx_rx_header.size, 1768c2ecf20Sopenharmony_ci quadlets) < 0) 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci snd_iprintf(buffer, "tx %u:\n", stream); 1798c2ecf20Sopenharmony_ci snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso); 1808c2ecf20Sopenharmony_ci snd_iprintf(buffer, " audio channels: %u\n", 1818c2ecf20Sopenharmony_ci buf.tx.number_audio); 1828c2ecf20Sopenharmony_ci snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi); 1838c2ecf20Sopenharmony_ci snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed); 1848c2ecf20Sopenharmony_ci if (quadlets >= 68) { 1858c2ecf20Sopenharmony_ci dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE); 1868c2ecf20Sopenharmony_ci snd_iprintf(buffer, " names: %s\n", buf.tx.names); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci if (quadlets >= 70) { 1898c2ecf20Sopenharmony_ci snd_iprintf(buffer, " ac3 caps: %08x\n", 1908c2ecf20Sopenharmony_ci buf.tx.ac3_caps); 1918c2ecf20Sopenharmony_ci snd_iprintf(buffer, " ac3 enable: %08x\n", 1928c2ecf20Sopenharmony_ci buf.tx.ac3_enable); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0) 1978c2ecf20Sopenharmony_ci return; 1988c2ecf20Sopenharmony_ci quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4); 1998c2ecf20Sopenharmony_ci for (stream = 0; stream < tx_rx_header.number; ++stream) { 2008c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 + 2018c2ecf20Sopenharmony_ci stream * tx_rx_header.size, 2028c2ecf20Sopenharmony_ci quadlets) < 0) 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci snd_iprintf(buffer, "rx %u:\n", stream); 2058c2ecf20Sopenharmony_ci snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso); 2068c2ecf20Sopenharmony_ci snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start); 2078c2ecf20Sopenharmony_ci snd_iprintf(buffer, " audio channels: %u\n", 2088c2ecf20Sopenharmony_ci buf.rx.number_audio); 2098c2ecf20Sopenharmony_ci snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi); 2108c2ecf20Sopenharmony_ci if (quadlets >= 68) { 2118c2ecf20Sopenharmony_ci dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE); 2128c2ecf20Sopenharmony_ci snd_iprintf(buffer, " names: %s\n", buf.rx.names); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci if (quadlets >= 70) { 2158c2ecf20Sopenharmony_ci snd_iprintf(buffer, " ac3 caps: %08x\n", 2168c2ecf20Sopenharmony_ci buf.rx.ac3_caps); 2178c2ecf20Sopenharmony_ci snd_iprintf(buffer, " ac3 enable: %08x\n", 2188c2ecf20Sopenharmony_ci buf.rx.ac3_enable); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4); 2238c2ecf20Sopenharmony_ci if (quadlets >= 4) { 2248c2ecf20Sopenharmony_ci if (dice_proc_read_mem(dice, &buf.ext_sync, 2258c2ecf20Sopenharmony_ci sections[6], 4) < 0) 2268c2ecf20Sopenharmony_ci return; 2278c2ecf20Sopenharmony_ci snd_iprintf(buffer, "ext status:\n"); 2288c2ecf20Sopenharmony_ci snd_iprintf(buffer, " clock source: %s\n", 2298c2ecf20Sopenharmony_ci str_from_array(clock_sources, 2308c2ecf20Sopenharmony_ci ARRAY_SIZE(clock_sources), 2318c2ecf20Sopenharmony_ci buf.ext_sync.clock_source)); 2328c2ecf20Sopenharmony_ci snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked); 2338c2ecf20Sopenharmony_ci snd_iprintf(buffer, " rate: %s\n", 2348c2ecf20Sopenharmony_ci str_from_array(rates, ARRAY_SIZE(rates), 2358c2ecf20Sopenharmony_ci buf.ext_sync.rate)); 2368c2ecf20Sopenharmony_ci snd_iprintf(buffer, " adat user data: "); 2378c2ecf20Sopenharmony_ci if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA) 2388c2ecf20Sopenharmony_ci snd_iprintf(buffer, "-\n"); 2398c2ecf20Sopenharmony_ci else 2408c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%x\n", 2418c2ecf20Sopenharmony_ci buf.ext_sync.adat_user_data); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void dice_proc_read_formation(struct snd_info_entry *entry, 2468c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci static const char *const rate_labels[] = { 2498c2ecf20Sopenharmony_ci [SND_DICE_RATE_MODE_LOW] = "low", 2508c2ecf20Sopenharmony_ci [SND_DICE_RATE_MODE_MIDDLE] = "middle", 2518c2ecf20Sopenharmony_ci [SND_DICE_RATE_MODE_HIGH] = "high", 2528c2ecf20Sopenharmony_ci }; 2538c2ecf20Sopenharmony_ci struct snd_dice *dice = entry->private_data; 2548c2ecf20Sopenharmony_ci int i, j; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Output stream from unit:\n"); 2578c2ecf20Sopenharmony_ci for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i) 2588c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%s", rate_labels[i]); 2598c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\tMIDI\n"); 2608c2ecf20Sopenharmony_ci for (i = 0; i < MAX_STREAMS; ++i) { 2618c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Tx %u:", i); 2628c2ecf20Sopenharmony_ci for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) 2638c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%u", dice->tx_pcm_chs[i][j]); 2648c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%u\n", dice->tx_midi_ports[i]); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Input stream to unit:\n"); 2688c2ecf20Sopenharmony_ci for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i) 2698c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%s", rate_labels[i]); 2708c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 2718c2ecf20Sopenharmony_ci for (i = 0; i < MAX_STREAMS; ++i) { 2728c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Rx %u:", i); 2738c2ecf20Sopenharmony_ci for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) 2748c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%u", dice->rx_pcm_chs[i][j]); 2758c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%u\n", dice->rx_midi_ports[i]); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void add_node(struct snd_dice *dice, struct snd_info_entry *root, 2808c2ecf20Sopenharmony_ci const char *name, 2818c2ecf20Sopenharmony_ci void (*op)(struct snd_info_entry *entry, 2828c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer)) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct snd_info_entry *entry; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci entry = snd_info_create_card_entry(dice->card, name, root); 2878c2ecf20Sopenharmony_ci if (entry) 2888c2ecf20Sopenharmony_ci snd_info_set_text_ops(entry, dice, op); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_civoid snd_dice_create_proc(struct snd_dice *dice) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct snd_info_entry *root; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * All nodes are automatically removed at snd_card_disconnect(), 2978c2ecf20Sopenharmony_ci * by following to link list. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci root = snd_info_create_card_entry(dice->card, "firewire", 3008c2ecf20Sopenharmony_ci dice->card->proc_root); 3018c2ecf20Sopenharmony_ci if (!root) 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci root->mode = S_IFDIR | 0555; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci add_node(dice, root, "dice", dice_proc_read); 3068c2ecf20Sopenharmony_ci add_node(dice, root, "formation", dice_proc_read_formation); 3078c2ecf20Sopenharmony_ci} 308