1*aa9e6044SNikita Kiryanov /* 2*aa9e6044SNikita Kiryanov * (C) Copyright 2009-2016 CompuLab, Ltd. 3*aa9e6044SNikita Kiryanov * 4*aa9e6044SNikita Kiryanov * Authors: Nikita Kiryanov <nikita@compulab.co.il> 5*aa9e6044SNikita Kiryanov * Igor Grinberg <grinberg@compulab.co.il> 6*aa9e6044SNikita Kiryanov * 7*aa9e6044SNikita Kiryanov * SPDX-License-Identifier: GPL-2.0+ 8*aa9e6044SNikita Kiryanov */ 9*aa9e6044SNikita Kiryanov 10*aa9e6044SNikita Kiryanov #include <common.h> 11*aa9e6044SNikita Kiryanov #include <linux/kernel.h> 12*aa9e6044SNikita Kiryanov #include <eeprom_layout.h> 13*aa9e6044SNikita Kiryanov #include <eeprom_field.h> 14*aa9e6044SNikita Kiryanov 15*aa9e6044SNikita Kiryanov #define NO_LAYOUT_FIELDS "Unknown layout. Dumping raw data\n" 16*aa9e6044SNikita Kiryanov 17*aa9e6044SNikita Kiryanov struct eeprom_field layout_unknown[1] = { 18*aa9e6044SNikita Kiryanov { NO_LAYOUT_FIELDS, 256, NULL, eeprom_field_print_bin, 19*aa9e6044SNikita Kiryanov eeprom_field_update_bin }, 20*aa9e6044SNikita Kiryanov }; 21*aa9e6044SNikita Kiryanov 22*aa9e6044SNikita Kiryanov /* 23*aa9e6044SNikita Kiryanov * eeprom_layout_detect() - detect layout based on the contents of the data. 24*aa9e6044SNikita Kiryanov * @data: Pointer to the data to be analyzed. 25*aa9e6044SNikita Kiryanov * 26*aa9e6044SNikita Kiryanov * Returns: the detected layout version. 27*aa9e6044SNikita Kiryanov */ 28*aa9e6044SNikita Kiryanov __weak int eeprom_layout_detect(unsigned char *data) 29*aa9e6044SNikita Kiryanov { 30*aa9e6044SNikita Kiryanov return LAYOUT_VERSION_UNRECOGNIZED; 31*aa9e6044SNikita Kiryanov } 32*aa9e6044SNikita Kiryanov 33*aa9e6044SNikita Kiryanov /* 34*aa9e6044SNikita Kiryanov * __eeprom_layout_assign() - set the layout fields 35*aa9e6044SNikita Kiryanov * @layout: A pointer to an existing struct layout. 36*aa9e6044SNikita Kiryanov * @layout_version: The version number of the desired layout 37*aa9e6044SNikita Kiryanov */ 38*aa9e6044SNikita Kiryanov __weak void __eeprom_layout_assign(struct eeprom_layout *layout, 39*aa9e6044SNikita Kiryanov int layout_version) 40*aa9e6044SNikita Kiryanov { 41*aa9e6044SNikita Kiryanov layout->fields = layout_unknown; 42*aa9e6044SNikita Kiryanov layout->num_of_fields = ARRAY_SIZE(layout_unknown); 43*aa9e6044SNikita Kiryanov } 44*aa9e6044SNikita Kiryanov void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version) \ 45*aa9e6044SNikita Kiryanov __attribute__((weak, alias("__eeprom_layout_assign"))); 46*aa9e6044SNikita Kiryanov 47*aa9e6044SNikita Kiryanov /* 48*aa9e6044SNikita Kiryanov * eeprom_layout_print() - print the layout and the data which is assigned to it 49*aa9e6044SNikita Kiryanov * @layout: A pointer to an existing struct layout. 50*aa9e6044SNikita Kiryanov */ 51*aa9e6044SNikita Kiryanov static void eeprom_layout_print(const struct eeprom_layout *layout) 52*aa9e6044SNikita Kiryanov { 53*aa9e6044SNikita Kiryanov int i; 54*aa9e6044SNikita Kiryanov struct eeprom_field *fields = layout->fields; 55*aa9e6044SNikita Kiryanov 56*aa9e6044SNikita Kiryanov for (i = 0; i < layout->num_of_fields; i++) 57*aa9e6044SNikita Kiryanov fields[i].print(&fields[i]); 58*aa9e6044SNikita Kiryanov } 59*aa9e6044SNikita Kiryanov 60*aa9e6044SNikita Kiryanov /* 61*aa9e6044SNikita Kiryanov * eeprom_layout_update_field() - update a single field in the layout data. 62*aa9e6044SNikita Kiryanov * @layout: A pointer to an existing struct layout. 63*aa9e6044SNikita Kiryanov * @field_name: The name of the field to update. 64*aa9e6044SNikita Kiryanov * @new_data: The new field data (a string. Format depends on the field) 65*aa9e6044SNikita Kiryanov * 66*aa9e6044SNikita Kiryanov * Returns: 0 on success, negative error value on failure. 67*aa9e6044SNikita Kiryanov */ 68*aa9e6044SNikita Kiryanov static int eeprom_layout_update_field(struct eeprom_layout *layout, 69*aa9e6044SNikita Kiryanov char *field_name, char *new_data) 70*aa9e6044SNikita Kiryanov { 71*aa9e6044SNikita Kiryanov int i, err; 72*aa9e6044SNikita Kiryanov struct eeprom_field *fields = layout->fields; 73*aa9e6044SNikita Kiryanov 74*aa9e6044SNikita Kiryanov if (new_data == NULL) 75*aa9e6044SNikita Kiryanov return 0; 76*aa9e6044SNikita Kiryanov 77*aa9e6044SNikita Kiryanov if (field_name == NULL) 78*aa9e6044SNikita Kiryanov return -1; 79*aa9e6044SNikita Kiryanov 80*aa9e6044SNikita Kiryanov for (i = 0; i < layout->num_of_fields; i++) { 81*aa9e6044SNikita Kiryanov if (fields[i].name == RESERVED_FIELDS || 82*aa9e6044SNikita Kiryanov strcmp(fields[i].name, field_name)) 83*aa9e6044SNikita Kiryanov continue; 84*aa9e6044SNikita Kiryanov 85*aa9e6044SNikita Kiryanov err = fields[i].update(&fields[i], new_data); 86*aa9e6044SNikita Kiryanov if (err) 87*aa9e6044SNikita Kiryanov printf("Invalid data for field %s\n", field_name); 88*aa9e6044SNikita Kiryanov 89*aa9e6044SNikita Kiryanov return err; 90*aa9e6044SNikita Kiryanov } 91*aa9e6044SNikita Kiryanov 92*aa9e6044SNikita Kiryanov printf("No such field '%s'\n", field_name); 93*aa9e6044SNikita Kiryanov 94*aa9e6044SNikita Kiryanov return -1; 95*aa9e6044SNikita Kiryanov } 96*aa9e6044SNikita Kiryanov 97*aa9e6044SNikita Kiryanov /* 98*aa9e6044SNikita Kiryanov * eeprom_layout_setup() - setup layout struct with the layout data and 99*aa9e6044SNikita Kiryanov * metadata as dictated by layout_version 100*aa9e6044SNikita Kiryanov * @layout: A pointer to an existing struct layout. 101*aa9e6044SNikita Kiryanov * @buf: A buffer initialized with the eeprom data. 102*aa9e6044SNikita Kiryanov * @buf_size: Size of buf in bytes. 103*aa9e6044SNikita Kiryanov * @layout version: The version number of the layout. 104*aa9e6044SNikita Kiryanov */ 105*aa9e6044SNikita Kiryanov void eeprom_layout_setup(struct eeprom_layout *layout, unsigned char *buf, 106*aa9e6044SNikita Kiryanov unsigned int buf_size, int layout_version) 107*aa9e6044SNikita Kiryanov { 108*aa9e6044SNikita Kiryanov int i; 109*aa9e6044SNikita Kiryanov 110*aa9e6044SNikita Kiryanov if (layout_version == LAYOUT_VERSION_AUTODETECT) 111*aa9e6044SNikita Kiryanov layout->layout_version = eeprom_layout_detect(buf); 112*aa9e6044SNikita Kiryanov else 113*aa9e6044SNikita Kiryanov layout->layout_version = layout_version; 114*aa9e6044SNikita Kiryanov 115*aa9e6044SNikita Kiryanov eeprom_layout_assign(layout, layout_version); 116*aa9e6044SNikita Kiryanov layout->data = buf; 117*aa9e6044SNikita Kiryanov for (i = 0; i < layout->num_of_fields; i++) { 118*aa9e6044SNikita Kiryanov layout->fields[i].buf = buf; 119*aa9e6044SNikita Kiryanov buf += layout->fields[i].size; 120*aa9e6044SNikita Kiryanov } 121*aa9e6044SNikita Kiryanov 122*aa9e6044SNikita Kiryanov layout->data_size = buf_size; 123*aa9e6044SNikita Kiryanov layout->print = eeprom_layout_print; 124*aa9e6044SNikita Kiryanov layout->update = eeprom_layout_update_field; 125*aa9e6044SNikita Kiryanov } 126