firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-scripts_dtc_updatetre...

748 lines
19 KiB
Diff

diff -drupN a/scripts/dtc/updatetree.c b/scripts/dtc/updatetree.c
--- a/scripts/dtc/updatetree.c 1970-01-01 03:00:00.000000000 +0300
+++ b/scripts/dtc/updatetree.c 2022-06-12 05:28:14.000000000 +0300
@@ -0,0 +1,743 @@
+#include "updatetree.h"
+
+extern struct script *script;
+
+/*public functions */
+int of_prop_string_count(const char *prop_val, int prop_len)
+{
+ int l = 0, i = 0;
+ const char *p, *end;
+
+ p = prop_val;
+ end = p + prop_len;
+
+ for (i = 0; p < end; i++, p += l) {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -1;
+ }
+
+ return i <= 0 ? -1 : i;
+}
+
+const char *of_prop_next_string(struct property *prop, const char *cur)
+{
+ const char *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur)
+ return prop->val.val;
+
+ curv += strlen(cur) + 1;
+ if (curv >= prop->val.val + prop->val.len)
+ return NULL;
+
+ return curv;
+}
+
+int sunxi_get_propval(struct node *node, const char *name)
+{
+ unsigned int value;
+ struct property *prop;
+ cell_t *info = NULL;
+
+ prop = get_property(node, name);
+ if (prop) {
+ info = (cell_t *)prop->val.val;
+ value = fdt32_to_cpu(*info++);
+ return value;
+ }
+
+ return -1;
+}
+
+int sunxi_gpio_to_name(int port, int port_num, char *name)
+{
+ int index;
+
+ if (!name)
+ return -1;
+
+ if ((port*32+port_num) >= 1024) {
+ /* axp gpio name like this : GPIO0/GPIO1/.. */
+ index = (port-1)*32+port_num - 1024;
+ sprintf(name, "GPIO%d", index);
+ } else {
+ /* sunxi gpio name like this : PA0/PA1/PB0 */
+ sprintf(name, "P%c%d", ('A' + (port-1)), port_num);
+ }
+
+ return 0;
+}
+
+/*these functions mainly to process pin subkey*/
+#define PL_BASE (352)
+#define AXP_BASE (1024)
+
+void sunxi_dt_update_gpio_group(struct dt_info *dti,
+ struct node *node,
+ struct script_entry *ep,
+ struct script_gpio_entry *entry)
+{
+ char *pinctrl_name = NULL, *string;
+ int val32, gpio_index, temp_val, phandle;
+ char *axp_pin_name[] = {"axp_pio", "axp_gpio0", "axp_gpio1"};
+ bool axp_pin = false;
+ int i;
+
+ struct data d;
+ struct property *prop;
+ struct node *pinctrl_node;
+
+ prop = get_property(node, ep->name);
+ if (prop)
+ delete_property(prop);
+
+ gpio_index = (entry->port - 1) * 32 + entry->port_num;
+ if (gpio_index < PL_BASE)
+ pinctrl_name = "pio";
+ else if (gpio_index < AXP_BASE && gpio_index >= PL_BASE)
+ pinctrl_name = "r_pio";
+ else
+ axp_pin = true;
+
+ if (axp_pin) {
+ for (i = 0; i < 3; i++) {
+ pinctrl_name = axp_pin_name[i];
+ pinctrl_node = sunxi_get_node(dti->dt, pinctrl_name);
+ if (pinctrl_node)
+ break;
+ }
+ } else {
+ pinctrl_node = sunxi_get_node(dti->dt, pinctrl_name);
+ }
+
+ if (!pinctrl_node) {
+ printf("warning:can't find gpio node %s\n", pinctrl_name);
+ return;
+ }
+
+ string = malloc(7 * sizeof(unsigned int));
+ /*set gpio control */
+ phandle = get_node_phandle(dti->dt, pinctrl_node);
+ val32 = cpu_to_fdt32(phandle);
+ memcpy(string, (char *)&val32, sizeof(val32));
+
+ /*set gpio bank */
+ val32 = cpu_to_fdt32(entry->port-1);
+ memcpy(string + 1 * sizeof(val32), (char *)&val32, sizeof(val32));
+
+ /*set gpio bank index */
+ val32 = cpu_to_fdt32(entry->port_num);
+ memcpy(string + 2 * sizeof(val32), (char *)&val32, sizeof(val32));
+
+ /*set gpio mul */
+ val32 = cpu_to_fdt32(entry->data[0]);
+ memcpy(string + 3 * sizeof(val32), (char *)&val32, sizeof(val32));
+
+ /*set gpio pull */
+ temp_val = entry->data[1] < 0 ? 0xFFFFFFFF : entry->data[1];
+ val32 = cpu_to_fdt32(temp_val);
+ memcpy(string + 4 * sizeof(val32), (char *)&val32, sizeof(val32));
+
+ /*set gpio drive */
+ temp_val = entry->data[2] < 0 ? 0xFFFFFFFF : entry->data[2];
+ val32 = cpu_to_fdt32(temp_val);
+ memcpy(string + 5 * sizeof(val32), (char *)&val32, sizeof(val32));
+
+ /*set gpio data */
+ temp_val = entry->data[3] < 0 ? 0xFFFFFFFF : entry->data[3];
+ val32 = cpu_to_fdt32(temp_val);
+ memcpy(string + 6 * sizeof(val32), (char *)&val32, sizeof(val32));
+
+ d = data_copy_mem(string, 7 * sizeof(unsigned int));
+ prop = build_property(ep->name, d);
+ add_property(node, prop);
+ free(string);
+}
+
+int sunxi_dt_init_pinconf_prop(struct script_section *section,
+ struct dt_info *dti,
+ struct node *node,
+ int sleep_state)
+{
+ int i, len, phandle;
+ cell_t *cp = NULL;
+
+ struct list_entry *o;
+ struct script_entry *ep;
+ struct script_gpio_entry *entry;
+
+ struct data d0;
+ struct node *p_node = NULL;
+ struct property *prop;
+ struct property *pinctrl;
+
+ /*remove pin config */
+ for_each_entry_in_section(section->entries, o) {
+ ep = container_of(o, struct script_entry, entries);
+ entry = container_of(ep, struct script_gpio_entry, entry);
+
+ if (entry->data[0] == 2 || entry->data[0] == 3 ||
+ entry->data[0] == 4 || entry->data[0] == 5 ||
+ entry->data[0] == 7) {
+ if (!sleep_state)
+ prop = get_property(node, "pinctrl-0");
+ else
+ prop = get_property(node, "pinctrl-1");
+
+ if (prop) {
+ len = prop->val.len/sizeof(unsigned int);
+ cp = (cell_t *)prop->val.val;
+ for (i = 0; i < len; i++) {
+ phandle = fdt32_to_cpu(*cp++);
+ p_node = get_node_by_phandle(dti->dt, phandle);
+ delete_node(p_node);
+ }
+ delete_property(prop);
+ }
+
+ /* build pinctrl-0 property */
+ d0 = data_copy_mem(NULL, 0);
+ if (!sleep_state)
+ pinctrl = build_property("pinctrl-0", d0);
+ else
+ pinctrl = build_property("pinctrl-1", d0);
+ add_property(node, pinctrl);
+
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
+cell_t sunxi_dt_add_new_node_to_pinctrl(struct node *pinctrl_node,
+ const char *dev_name,
+ const char *pname,
+ char *gpio_name,
+ int gpio_value[],
+ struct dt_info *dti)
+{
+ cell_t phandle;
+ int i, value_32, len, str_len;
+ char *label, node_name[32];
+ struct data d;
+ struct node *child, *temp_node;
+ struct property *prop;
+ child = build_node(NULL, NULL);
+
+ /* set label */
+ str_len = strlen(dev_name)+strlen("_pins_")+2;
+ label = malloc(str_len);
+ strcpy(label, dev_name);
+ strcat(label, "_pins_");
+
+ for (i = 0; i < 8; i++) {
+ label[str_len-2] = (char)(i+'a');
+ label[str_len-1] = '\0';
+ temp_node = sunxi_get_node(dti->dt, label);
+ if (temp_node)
+ continue;
+ else
+ break;
+ }
+ add_label(&child->labels, label);
+
+ /*set node name*/
+ str_len = strlen(dev_name)+2;
+ strcpy(node_name, dev_name);
+ strcat(node_name, "@");
+ for (i = 0; i < 8; i++) {
+ node_name[str_len-1] = (char)(i+'0');
+ node_name[str_len] = '\0';
+ temp_node = get_subnode(pinctrl_node, node_name);
+ if (temp_node)
+ continue;
+ else
+ break;
+ }
+
+ /* set node name and phandle*/
+ child->name = xstrdup(node_name);
+
+ /* set fullpath */
+ child->fullpath = join_path(pinctrl_node->fullpath, child->name);
+
+ /*set phandle*/
+ phandle = get_node_phandle(dti->dt, child);
+ add_child(pinctrl_node, child);
+
+ /*add property of pins */
+ d = data_copy_mem(gpio_name, strlen(gpio_name) + 1);
+ prop = build_property("allwinner,pins", d);
+ add_property(child, prop);
+
+ d = data_copy_mem(dev_name, strlen(dev_name) + 1);
+ prop = build_property("allwinner,function", d);
+ add_property(child, prop);
+
+ d = data_copy_mem(pname, strlen(pname) + 1);
+ prop = build_property("allwinner,pname", d);
+ add_property(child, prop);
+
+ value_32 = cpu_to_fdt32(gpio_value[0]);
+ len = sizeof(unsigned int);
+ d = data_copy_mem((char *)&value_32, len);
+ prop = build_property("allwinner,muxsel", d);
+ add_property(child, prop);
+
+ value_32 = cpu_to_fdt32(gpio_value[1]);
+ len = sizeof(unsigned int);
+ d = data_copy_mem((char *)&value_32, len);
+ prop = build_property("allwinner,pull", d);
+ add_property(child, prop);
+
+ value_32 = cpu_to_fdt32(gpio_value[2]);
+ len = sizeof(unsigned int);
+ d = data_copy_mem((char *)&value_32, len);
+ prop = build_property("allwinner,drive", d);
+ add_property(child, prop);
+
+ value_32 = cpu_to_fdt32(gpio_value[3]);
+ len = sizeof(unsigned int);
+ d = data_copy_mem((char *)&value_32, len);
+ prop = build_property("allwinner,data", d);
+ add_property(child, prop);
+
+ return phandle;
+
+}
+int insert_pinconf_node(const char *section_name,
+ struct dt_info *dti,
+ struct node *node,
+ struct script_entry *ep,
+ const char *prop_name)
+{
+ char gpio_name[32], *string;
+ cell_t *cp, *info;
+ int muxsel = 0, pull = 0, data = 0, drive = 0;
+ int i, ret, len, gpio_value[4], phandle, phandle_count;
+
+ struct node *pin_node;
+ struct property *prop, *prop_temp;
+ struct script_gpio_entry *entry;
+
+ entry = container_of(ep, struct script_gpio_entry, entry);
+ ret = sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name);
+ if (ret)
+ return ret;
+
+ gpio_value[0] = entry->data[0];
+ gpio_value[1] = entry->data[1] < 0 ? 0xFFFFFFFF : entry->data[1];
+ gpio_value[2] = entry->data[2] < 0 ? 0xFFFFFFFF : entry->data[2];
+ gpio_value[3] = entry->data[3] < 0 ? 0xFFFFFFFF : entry->data[3];
+
+ prop = get_property(node, prop_name);
+ phandle_count = prop->val.len/sizeof(unsigned int);
+ cp = (cell_t *)prop->val.val;
+
+ for (i = 0; i < phandle_count; i++) {
+ phandle = fdt32_to_cpu(*cp++);
+ pin_node = get_node_by_phandle(dti->dt, phandle);
+
+ if (pin_node) {
+ /* if find a pinctrl node, check config*/
+ prop_temp = get_property(pin_node, "allwinner,muxsel");
+ if (prop_temp) {
+ info = (cell_t *)prop_temp->val.val;
+ muxsel = fdt32_to_cpu(*info++);
+ }
+ prop_temp = get_property(pin_node, "allwinner,pull");
+ if (prop_temp) {
+ info = (cell_t *)prop_temp->val.val;
+ pull = fdt32_to_cpu(*info++);
+ }
+ prop_temp = get_property(pin_node, "allwinner,drive");
+ if (prop_temp) {
+ info = (cell_t *)prop_temp->val.val;
+ drive = fdt32_to_cpu(*info++);
+ }
+ prop_temp = get_property(pin_node, "allwinner,data");
+ if (prop_temp) {
+ info = (cell_t *)prop_temp->val.val;
+ data = fdt32_to_cpu(*info++);
+ }
+
+ if (gpio_value[0] == muxsel && gpio_value[1] == pull &&
+ gpio_value[2] == drive && gpio_value[3] == data) {
+ prop_temp = get_property(pin_node, "allwinner,pins");
+ if (prop_temp) {
+ len = prop_temp->val.len + strlen(gpio_name) + 1;
+ string = malloc(len);
+ memcpy(string, prop_temp->val.val, prop_temp->val.len);
+ memcpy(string + prop_temp->val.len, gpio_name, strlen(gpio_name));
+ string[len-1] = '\0';
+ free(prop_temp->val.val);
+ prop_temp->val.val = malloc(len);
+ memcpy(prop_temp->val.val, string, len);
+ prop_temp->val.len = len;
+ free(string);
+ }
+
+ prop_temp = get_property(pin_node, "allwinner,pname");
+ if (prop_temp) {
+ len = prop_temp->val.len + strlen(ep->name) + 1;
+ string = malloc(len);
+ memcpy(string, prop_temp->val.val, prop_temp->val.len);
+ memcpy(string + prop_temp->val.len, ep->name, strlen(ep->name));
+ string[len-1] = '\0';
+ free(prop_temp->val.val);
+ prop_temp->val.val = malloc(len);
+ memcpy(prop_temp->val.val, string, len);
+ prop_temp->val.len = len;
+ free(string);
+ return 0;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+void create_pinconf_node(const char *section_name,
+ struct dt_info *dti,
+ struct node *node,
+ struct script_entry *ep,
+ struct property *prop)
+{
+ int value[4], phandle;
+ char gpio_name[32], *propname;
+ struct node *pinctrl = NULL;
+ struct data d_pinctrl_x;
+ struct property *pinctrl_x;
+ struct script_gpio_entry *entry;
+
+ entry = container_of(ep, struct script_gpio_entry, entry);
+ sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name);
+ value[0] = entry->data[0];
+ value[1] = entry->data[1] < 0 ? 0xFFFFFFFF : entry->data[1];
+ value[2] = entry->data[2] < 0 ? 0xFFFFFFFF : entry->data[2];
+ value[3] = entry->data[3] < 0 ? 0xFFFFFFFF : entry->data[3];
+
+ if (entry->port * 32 < PL_BASE)
+ pinctrl = sunxi_get_node(dti->dt, "pio");
+ else if (entry->port * 32 >= PL_BASE && entry->port < AXP_BASE)
+ pinctrl = sunxi_get_node(dti->dt, "r_pio");
+
+ phandle = sunxi_dt_add_new_node_to_pinctrl(pinctrl, section_name, ep->name, gpio_name, value, dti);
+ if (phandle) {
+ d_pinctrl_x = data_append_cell(prop->val, phandle);
+ propname = malloc(strlen(prop->name));
+ strcpy(propname, prop->name);
+ delete_property(prop);
+ pinctrl_x = build_property(propname, d_pinctrl_x);
+ add_property(node, pinctrl_x);
+ }
+}
+
+void sunxi_dt_update_pin_group_sleep(const char *section_name,
+ struct dt_info *dti,
+ struct node *node,
+ struct script_entry *ep)
+{
+ int ret = 0;
+ char gpio_name[32] = {0};
+ struct property *prop;
+ struct script_gpio_entry *entry;
+
+ entry = container_of(ep, struct script_gpio_entry, entry);
+ sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name);
+ prop = get_property(node, "pinctrl-1");
+
+ ret = insert_pinconf_node(section_name, dti, node, ep, "pinctrl-1");
+ if (ret)
+ create_pinconf_node(section_name, dti, node, ep, prop);
+}
+
+
+void sunxi_dt_update_pin_group_default(const char *section_name,
+ struct dt_info *dti,
+ struct node *node,
+ struct script_entry *ep)
+{
+ int ret = 0;
+ char gpio_name[32] = {0};
+
+ struct property *prop;
+ struct script_gpio_entry *entry;
+
+ entry = container_of(ep, struct script_gpio_entry, entry);
+ sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name);
+ prop = get_property(node, "pinctrl-0");
+
+ ret = insert_pinconf_node(section_name, dti, node, ep, "pinctrl-0");
+ if (ret)
+ create_pinconf_node(section_name, dti, node, ep, prop);
+}
+
+/*end process pinconf */
+
+void sunxi_dt_update_propval_cells(const char *section_name,
+ struct script_entry *ep,
+ struct node *node)
+{
+ int len;
+ unsigned int value_32;
+ char temp[32], *string;
+ struct data d;
+ struct property *prop;
+ struct script_single_entry *entry;
+
+ entry = container_of(ep, struct script_single_entry, entry);
+ strcpy(temp, section_name);
+ strcat(temp, "_used");
+
+ if (strcmp(ep->name, "used") == 0 || strcmp(ep->name, temp) == 0) {
+
+ string = entry->value ? "okay" : "disabled";
+ len = strlen(string) + 1;
+ prop = get_property(node, "status");
+
+ if (prop) {
+ free(prop->val.val);
+ prop->val.val = malloc(len);
+ strcpy(prop->val.val, string);
+ prop->val.len = len;
+ } else {
+ d = data_copy_mem(string, len);
+ prop = build_property("status", d);
+ add_property(node, prop);
+ }
+ } else {
+ value_32 = cpu_to_fdt32(entry->value);
+ len = sizeof(unsigned int);
+ prop = get_property(node, ep->name);
+
+ if (prop) {
+ free(prop->val.val);
+ prop->val.val = malloc(len);
+ memcpy(prop->val.val, &value_32, len);
+ prop->val.len = len;
+ } else {
+ d = data_copy_mem((char *)&value_32, len);
+ prop = build_property(ep->name, d);
+ add_property(node, prop);
+ }
+ }
+}
+
+void sunxi_dt_update_propval_string(const char *section_name,
+ struct script_entry *ep,
+ struct node *node)
+{
+ int len;
+ char *string;
+
+ struct data d;
+ struct property *prop;
+ struct script_string_entry *entry;
+
+ /*SCRIPT_VALUE_TYPE_STRING*/
+ entry = container_of(ep, struct script_string_entry, entry);
+ string = entry->string;
+ len = entry->l;
+
+ prop = get_property(node, ep->name);
+ if (prop) {
+ free(prop->val.val);
+ prop->val.val = malloc(len);
+ strcpy(prop->val.val, string);
+ prop->val.len = len;
+ } else {
+ d = data_copy_mem(string, len);
+ prop = build_property(ep->name, d);
+ add_property(node, prop);
+ }
+}
+
+void sunxi_dt_update_propval_empty(const char *section_name,
+ struct script_entry *ep,
+ struct node *node)
+{
+ struct data d = {0};
+ struct property *prop, *temp;
+ struct script_null_entry *entry;
+
+ /* SCRIPT_VALUE_TYPE_STRING */
+ entry = container_of(ep, struct script_null_entry, entry);
+
+ prop = get_property(node, entry->entry.name);
+ if (prop)
+ delete_property(prop);
+
+ temp = build_property(entry->entry.name, d);
+ add_property(node, temp);
+}
+
+void sunxi_dt_update_propval_gpio(const char *section_name,
+ struct script_entry *ep,
+ struct node *node,
+ struct dt_info *dti,
+ int sleep_state)
+{
+ struct script_gpio_entry *entry;
+ entry = container_of(ep, struct script_gpio_entry, entry);
+
+ switch (entry->data[0]) {
+ case 0:
+ case 1:
+ case 6:
+ sunxi_dt_update_gpio_group(dti, node, ep, entry);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ if (sleep_state)
+ sunxi_dt_update_pin_group_sleep(section_name, dti, node, ep);
+ else
+ sunxi_dt_update_pin_group_default(section_name, dti, node, ep);
+ break;
+ }
+
+}
+struct node *sunxi_get_node(struct node *tree, const char *string)
+{
+ struct node *nd;
+
+ nd = get_node_by_label(tree, string);
+ if (!nd)
+ nd = get_node_by_type(tree, string);
+
+ return nd;
+}
+
+int sunxi_build_new_node(struct dt_info *dti, char pnode_name[], char node_name[])
+{
+ char *label;
+ struct node *child, *parent;
+
+ parent = sunxi_get_node(dti->dt, pnode_name);
+ child = build_node(NULL, NULL);
+ if (!child)
+ printf("build node faile[%s]\n", node_name);
+
+ label = xstrdup(node_name);
+ add_label(&child->labels, label);
+ child->name = xstrdup(node_name);
+ child->fullpath = join_path(parent->fullpath, child->name);
+ add_child(parent, child);
+
+ return 0;
+}
+
+int process_mainkey(char *mainkey, char parent_name[], char child_name[], int *state)
+{
+ char *delim1 = "/";
+ char *delim2 = "_suspend";
+ char *buf = strstr(mainkey, delim1);
+ char *temp_buf;
+
+ if (buf != NULL) {
+ sscanf(mainkey, "%31[^/]/%31[^@]", parent_name, child_name);
+ } else {
+ strcpy(parent_name, "soc");
+ strcpy(child_name, mainkey);
+ }
+
+ temp_buf = strstr(child_name, delim2);
+ if (temp_buf != NULL) {
+ memset(temp_buf, 0, strlen(temp_buf));
+ *state = 1;
+ } else {
+ *state = 0;
+ }
+
+ return 0;
+}
+
+int dt_update_source(const char *fexname, FILE *f, struct dt_info *dti)
+{
+
+ int ret = 0;
+ int sleep_state = false;
+ char p_key[32] = {0};
+ char c_key[32] = {0};
+
+ struct node *sub_node, *parent_node;
+ struct list_entry *sec_list, *o;
+ struct script_section *section;
+ struct script_entry *ep;
+ struct property *device_type_prop;
+
+ /*for build new device type property.*/
+ struct data d;
+ struct property *new_prop;
+
+ ret = script_parse(fexname);
+ if (ret) {
+ printf("parser sys_config.fex file failed.\n");
+ exit(1);
+ }
+
+ for_each_section_in_list(script->sections, sec_list) {
+ section = container_of(sec_list,
+ struct script_section, sections);
+ /*
+ * here mainly deal with section name like parent_key/child_key
+ */
+ process_mainkey(section->name, p_key, c_key, &sleep_state);
+ printf("p=%s c=%s state=%d\n", p_key, c_key, sleep_state);
+
+ parent_node = sunxi_get_node(dti->dt, p_key);
+ if (!parent_node) {
+ printf("[SCRIPT_TO_DTS]Can not get parent node.\n");
+ exit(1);
+ }
+
+ sub_node = sunxi_get_node(dti->dt, c_key);
+ if (!sub_node) {
+ sunxi_build_new_node(dti, p_key, c_key);
+ sub_node = sunxi_get_node(dti->dt, c_key);
+ }
+
+ device_type_prop = get_property(sub_node, "device_type");
+ if (!device_type_prop) {
+ d = data_copy_mem(c_key, strlen(c_key)+1);
+ new_prop = build_property("device_type", d);
+ add_property(sub_node, new_prop);
+ }
+
+ sunxi_dt_init_pinconf_prop(section, dti, sub_node, sleep_state);
+ for_each_entry_in_section(section->entries, o) {
+ ep = container_of(o, struct script_entry, entries);
+ switch (ep->type) {
+ case 1:
+ case 2:
+ sunxi_dt_update_propval_cells(c_key, ep, sub_node);
+ break;
+ case 3:
+ sunxi_dt_update_propval_string(c_key, ep, sub_node);
+ break;
+ case 5:
+ sunxi_dt_update_propval_gpio(c_key, ep, sub_node, dti, sleep_state);
+ break;
+ case 6:
+ /*empty property */
+ sunxi_dt_update_propval_empty(c_key, ep, sub_node);
+ break;
+ default:
+ printf("input type error.\n");
+ break;
+ }
+ }
+ }
+
+ return 0;
+}