/* * Copyright (C) 2015 Juergen Borleis <kernel@pengutronix.de> * * Based on code from: * Copyright (C) 2013 Jan Luebbe <j.luebbe@pengutronix.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <common.h> #include <errno.h> #include <fcntl.h> #include <fs.h> #include <globalvar.h> #include <xfuncs.h> #include <init.h> #include <net.h> #define PCM030_EEPROM_DEVICE "/dev/eeprom0" /* * The first 2048 bytes contain the U-Boot environment shipped with the boards. * After that an area begins where some board specific and partially unique data * is stored. All of this data is plain test, string delimiter is the semicolon. * the last string terminates with a '\0'. * One example found in the 'product' area: PCM-030-02REI;017822;0050C2875974\0 * The first string seems to be the product type, the second string some kind * of serial number and the last string the boards unique MAC. */ struct pcm030_eeprom { char env[0x800]; /* u-boot environment */ char product[0x80]; /* <product>;<serno>;<mac>\0 */ } __attribute__((packed)); static void pcm030_read_factory_data(const struct pcm030_eeprom *buf) { unsigned u, l; char *board, *serial; char *full_mac = "xx:xx:xx:xx:xx:xx"; u8 enetaddr[6]; u = 0; for (l = 0; (l + u) < sizeof(buf->product); l++) { if (buf->product[u + l] != ';') continue; board = xstrndup(&buf->product[u], l); u += l + 1; globalvar_add_simple("model.type", board); free(board); } for (l = 0; (l + u) < sizeof(buf->product); l++) { if (buf->product[u + l] != ';') continue; serial = xstrndup(&buf->product[u], l); u += l + 1; globalvar_add_simple("model.serial", serial); free(serial); } /* for the MAC do a simple duck test */ if (buf->product[u] != ';' && buf->product[u + 12] == '\0') { full_mac[0] = buf->product[u + 0]; full_mac[1] = buf->product[u + 1]; full_mac[3] = buf->product[u + 2]; full_mac[4] = buf->product[u + 3]; full_mac[6] = buf->product[u + 4]; full_mac[7] = buf->product[u + 5]; full_mac[9] = buf->product[u + 6]; full_mac[10] = buf->product[u + 7]; full_mac[12] = buf->product[u + 8]; full_mac[13] = buf->product[u + 9]; full_mac[15] = buf->product[u + 10]; full_mac[16] = buf->product[u + 11]; string_to_ethaddr(full_mac, enetaddr); eth_register_ethaddr(0, enetaddr); return; } printf("EEPROM contains no ethernet MAC\n"); } static int pcm030_eeprom_read(void) { int fd, ret; struct pcm030_eeprom *buf; fd = open(PCM030_EEPROM_DEVICE, O_RDONLY); if (fd < 0) { perror("failed to open " PCM030_EEPROM_DEVICE); return fd; } buf = xmalloc(sizeof(struct pcm030_eeprom)); ret = pread(fd, buf, sizeof(struct pcm030_eeprom), 0); if (ret < sizeof(struct pcm030_eeprom)) { perror("failed to read " PCM030_EEPROM_DEVICE); goto out; } pcm030_read_factory_data(buf); ret = 0; out: free(buf); close(fd); return ret; } late_initcall(pcm030_eeprom_read);