mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 08:31:52 +00:00
servo_micro: add programmable serial number
This change provides a console command for setting, and loading a usb serial number from flash. This feature adds CONFIG_USB_SERIALNO, and currently only has a useful implementation when PSTATE is present. BUG=chromium:571477 TEST=serialno set abcdef; serialno load; reboot BRANCH=none Change-Id: I3b24cfa2d52d54118bc3fd54b276e3d95412d245 Signed-off-by: Nick Sanders <nsanders@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/337359 Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
@@ -154,12 +154,11 @@ USB_STREAM_CONFIG(usart4_usb,
|
||||
/******************************************************************************
|
||||
* Define the strings used in our USB descriptors.
|
||||
*/
|
||||
|
||||
const void *const usb_strings[] = {
|
||||
[USB_STR_DESC] = usb_string_desc,
|
||||
[USB_STR_VENDOR] = USB_STRING_DESC("Google Inc."),
|
||||
[USB_STR_PRODUCT] = USB_STRING_DESC("Servo Micro"),
|
||||
[USB_STR_SERIALNO] = USB_STRING_DESC("1234-a"),
|
||||
[USB_STR_SERIALNO] = 0,
|
||||
[USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32),
|
||||
[USB_STR_USART4_STREAM_NAME] = USB_STRING_DESC("Servo UART3"),
|
||||
[USB_STR_CONSOLE_NAME] = USB_STRING_DESC("Servo EC Shell"),
|
||||
@@ -169,7 +168,6 @@ const void *const usb_strings[] = {
|
||||
|
||||
BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Support SPI bridging over USB, this requires usb_spi_board_enable and
|
||||
* usb_spi_board_disable to be defined to enable and disable the SPI bridge.
|
||||
|
||||
@@ -87,6 +87,9 @@
|
||||
|
||||
#include "gpio_signal.h"
|
||||
|
||||
#define CONFIG_USB_SERIALNO
|
||||
#define DEFAULT_SERIALNO "Uninitialized"
|
||||
|
||||
/* USB string indexes */
|
||||
enum usb_strings {
|
||||
USB_STR_DESC = 0,
|
||||
|
||||
112
chip/stm32/usb.c
112
chip/stm32/usb.c
@@ -7,6 +7,7 @@
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include "flash.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "link_defs.h"
|
||||
@@ -34,6 +35,12 @@
|
||||
#define CONFIG_USB_BCD_DEV 0x0100 /* 1.00 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USB_SERIALNO
|
||||
#define USB_STR_SERIALNO 0
|
||||
#else
|
||||
static int usb_load_serial(void);
|
||||
#endif
|
||||
|
||||
/* USB Standard Device Descriptor */
|
||||
static const struct usb_device_descriptor dev_desc = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
@@ -48,7 +55,7 @@ static const struct usb_device_descriptor dev_desc = {
|
||||
.bcdDevice = CONFIG_USB_BCD_DEV,
|
||||
.iManufacturer = USB_STR_VENDOR,
|
||||
.iProduct = USB_STR_PRODUCT,
|
||||
.iSerialNumber = 0,
|
||||
.iSerialNumber = USB_STR_SERIALNO,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
@@ -85,6 +92,8 @@ static int desc_left;
|
||||
/* pointer to descriptor data if any */
|
||||
static const uint8_t *desc_ptr;
|
||||
|
||||
|
||||
|
||||
void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet)
|
||||
{
|
||||
packet->bmRequestType = buffer[0] & 0xff;
|
||||
@@ -137,7 +146,12 @@ static void ep0_rx(void)
|
||||
if (idx >= USB_STR_COUNT)
|
||||
/* The string does not exist : STALL */
|
||||
goto unknown_req;
|
||||
desc = usb_strings[idx];
|
||||
#ifdef CONFIG_USB_SERIALNO
|
||||
if (idx == USB_STR_SERIALNO)
|
||||
desc = (uint8_t *)usb_serialno_desc;
|
||||
else
|
||||
#endif
|
||||
desc = usb_strings[idx];
|
||||
len = desc[0];
|
||||
break;
|
||||
case USB_DT_DEVICE_QUALIFIER: /* Get device qualifier desc */
|
||||
@@ -307,6 +321,9 @@ void usb_init(void)
|
||||
/* set interrupts mask : reset/correct tranfer/errors */
|
||||
STM32_USB_CNTR = 0xe400;
|
||||
|
||||
#ifdef CONFIG_USB_SERIALNO
|
||||
usb_load_serial();
|
||||
#endif
|
||||
#ifndef CONFIG_USB_INHIBIT_CONNECT
|
||||
usb_connect();
|
||||
#endif
|
||||
@@ -402,3 +419,94 @@ void *memcpy_from_usbram(void *dest, const void *src, size_t n)
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_SERIALNO
|
||||
/* This will be subbed into USB_STR_SERIALNO. */
|
||||
struct usb_string_desc *usb_serialno_desc =
|
||||
USB_WR_STRING_DESC(DEFAULT_SERIALNO);
|
||||
|
||||
/* Update serial number */
|
||||
static int usb_set_serial(const char *serialno)
|
||||
{
|
||||
struct usb_string_desc *sd = usb_serialno_desc;
|
||||
int i;
|
||||
|
||||
if (!serialno)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
/* Convert into unicode usb string desc. */
|
||||
for (i = 0; i < USB_STRING_LEN; i++) {
|
||||
sd->_data[i] = serialno[i];
|
||||
if (serialno[i] == 0)
|
||||
break;
|
||||
}
|
||||
/* Count wchars (w/o null terminator) plus size & type bytes. */
|
||||
sd->_len = (i * 2) + 2;
|
||||
sd->_type = USB_DT_STRING;
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Retrieve serial number from pstate flash. */
|
||||
static int usb_load_serial(void)
|
||||
{
|
||||
const char *serialno;
|
||||
int rv;
|
||||
|
||||
serialno = flash_read_serial();
|
||||
if (!serialno)
|
||||
return EC_ERROR_ACCESS_DENIED;
|
||||
|
||||
rv = usb_set_serial(serialno);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Save serial number into pstate region. */
|
||||
static int usb_save_serial(const char *serialno)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!serialno)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
/* Save this new serial number to flash. */
|
||||
rv = flash_write_serial(serialno);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* Load this new serial number to memory. */
|
||||
rv = usb_load_serial();
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int command_serialno(int argc, char **argv)
|
||||
{
|
||||
struct usb_string_desc *sd = usb_serialno_desc;
|
||||
char buf[USB_STRING_LEN];
|
||||
int rv = EC_SUCCESS;
|
||||
int i;
|
||||
|
||||
if (argc != 1) {
|
||||
if ((strcasecmp(argv[1], "set") == 0) &&
|
||||
(argc == 3)) {
|
||||
ccprintf("Saving serial number\n");
|
||||
rv = usb_save_serial(argv[2]);
|
||||
} else if ((strcasecmp(argv[1], "load") == 0) &&
|
||||
(argc == 2)) {
|
||||
ccprintf("Loading serial number\n");
|
||||
rv = usb_load_serial();
|
||||
} else
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < USB_STRING_LEN; i++)
|
||||
buf[i] = sd->_data[i];
|
||||
ccprintf("Serial number: %s\n", buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
DECLARE_CONSOLE_COMMAND(serialno, command_serialno,
|
||||
"load/set [value]",
|
||||
"Read and write USB serial number",
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
172
common/flash.c
172
common/flash.c
@@ -35,17 +35,24 @@
|
||||
|
||||
#ifdef CONFIG_FLASH_PSTATE_BANK
|
||||
/* Persistent protection state - emulates a SPI status register for flashrom */
|
||||
struct persist_state {
|
||||
uint8_t version; /* Version of this struct */
|
||||
uint8_t flags; /* Lock flags (PERSIST_FLAG_*) */
|
||||
uint8_t reserved[2]; /* Reserved; set 0 */
|
||||
};
|
||||
|
||||
#define PERSIST_STATE_VERSION 2 /* Expected persist_state.version */
|
||||
/* NOTE: It's not expected that RO and RW will support
|
||||
* differing PSTATE versions. */
|
||||
#define PERSIST_STATE_VERSION 3 /* Expected persist_state.version */
|
||||
#define SERIALNO_MAX 30
|
||||
|
||||
/* Flags for persist_state.flags */
|
||||
/* Protect persist state and RO firmware at boot */
|
||||
#define PERSIST_FLAG_PROTECT_RO 0x02
|
||||
#define PSTATE_VALID_FLAGS (1 << 0)
|
||||
#define PSTATE_VALID_SERIALNO (1 << 1)
|
||||
|
||||
struct persist_state {
|
||||
uint8_t version; /* Version of this struct */
|
||||
uint8_t flags; /* Lock flags (PERSIST_FLAG_*) */
|
||||
uint8_t valid_fields; /* Flags for valid data. */
|
||||
uint8_t reserved; /* Reserved; set 0 */
|
||||
uint8_t serialno[SERIALNO_MAX]; /* Serial number. */
|
||||
};
|
||||
|
||||
#else /* !CONFIG_FLASH_PSTATE_BANK */
|
||||
|
||||
@@ -142,6 +149,7 @@ static uint32_t flash_read_pstate(void)
|
||||
flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
|
||||
|
||||
if ((pstate->version == PERSIST_STATE_VERSION) &&
|
||||
(pstate->valid_fields & PSTATE_VALID_FLAGS) &&
|
||||
(pstate->flags & PERSIST_FLAG_PROTECT_RO)) {
|
||||
/* Lock flag is known to be set */
|
||||
return EC_FLASH_PROTECT_RO_AT_BOOT;
|
||||
@@ -155,23 +163,33 @@ static uint32_t flash_read_pstate(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Write persistent state from pstate, erasing if necessary.
|
||||
* Read and return persistent serial number.
|
||||
*/
|
||||
static const char *flash_read_pstate_serial(void)
|
||||
{
|
||||
const struct persist_state *pstate =
|
||||
(const struct persist_state *)
|
||||
flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
|
||||
|
||||
if ((pstate->version == PERSIST_STATE_VERSION) &&
|
||||
(pstate->valid_fields & PSTATE_VALID_SERIALNO)) {
|
||||
return (const char *)(pstate->serialno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write persistent state after erasing.
|
||||
*
|
||||
* @param flags New flash write protect flags to set in pstate.
|
||||
* @param pstate New data to set in pstate. NOT memory mapped
|
||||
* old pstate as it will be erased.
|
||||
* @return EC_SUCCESS, or nonzero if error.
|
||||
*/
|
||||
static int flash_write_pstate(uint32_t flags)
|
||||
static int flash_write_pstate_data(struct persist_state *newpstate)
|
||||
{
|
||||
struct persist_state pstate;
|
||||
int rv;
|
||||
|
||||
/* Only check the flags we write to pstate */
|
||||
flags &= EC_FLASH_PROTECT_RO_AT_BOOT;
|
||||
|
||||
/* Check if pstate has actually changed */
|
||||
if (flags == flash_read_pstate())
|
||||
return EC_SUCCESS;
|
||||
|
||||
/* Erase pstate */
|
||||
rv = flash_physical_erase(CONFIG_FW_PSTATE_OFF,
|
||||
CONFIG_FW_PSTATE_SIZE);
|
||||
@@ -184,15 +202,101 @@ static int flash_write_pstate(uint32_t flags)
|
||||
* it's protected.
|
||||
*/
|
||||
|
||||
/* Write a new pstate */
|
||||
memset(&pstate, 0, sizeof(pstate));
|
||||
pstate.version = PERSIST_STATE_VERSION;
|
||||
if (flags & EC_FLASH_PROTECT_RO_AT_BOOT)
|
||||
pstate.flags |= PERSIST_FLAG_PROTECT_RO;
|
||||
return flash_physical_write(CONFIG_FW_PSTATE_OFF, sizeof(pstate),
|
||||
(const char *)&pstate);
|
||||
/* Write the updated pstate */
|
||||
return flash_physical_write(CONFIG_FW_PSTATE_OFF, sizeof(*newpstate),
|
||||
(const char *)newpstate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Validate and Init persistent state datastructure.
|
||||
*
|
||||
* @param pstate A pstate data structure. Will be valid at complete.
|
||||
* @return EC_SUCCESS, or nonzero if error.
|
||||
*/
|
||||
static int validate_pstate_struct(struct persist_state *pstate)
|
||||
{
|
||||
if (pstate->version != PERSIST_STATE_VERSION) {
|
||||
memset(pstate, 0, sizeof(*pstate));
|
||||
pstate->version = PERSIST_STATE_VERSION;
|
||||
pstate->valid_fields = 0;
|
||||
}
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write persistent state from pstate, erasing if necessary.
|
||||
*
|
||||
* @param flags New flash write protect flags to set in pstate.
|
||||
* @return EC_SUCCESS, or nonzero if error.
|
||||
*/
|
||||
static int flash_write_pstate(uint32_t flags)
|
||||
{
|
||||
struct persist_state newpstate;
|
||||
const struct persist_state *pstate =
|
||||
(const struct persist_state *)
|
||||
flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
|
||||
|
||||
/* Only check the flags we write to pstate */
|
||||
flags &= EC_FLASH_PROTECT_RO_AT_BOOT;
|
||||
|
||||
/* Check if pstate has actually changed */
|
||||
if (flags == flash_read_pstate())
|
||||
return EC_SUCCESS;
|
||||
|
||||
/* Cache the old copy for read/modify/write. */
|
||||
memcpy(&newpstate, pstate, sizeof(newpstate));
|
||||
validate_pstate_struct(&newpstate);
|
||||
|
||||
if (flags & EC_FLASH_PROTECT_RO_AT_BOOT)
|
||||
newpstate.flags |= PERSIST_FLAG_PROTECT_RO;
|
||||
else
|
||||
newpstate.flags &= ~PERSIST_FLAG_PROTECT_RO;
|
||||
newpstate.valid_fields |= PSTATE_VALID_FLAGS;
|
||||
|
||||
return flash_write_pstate_data(&newpstate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write persistent serial number to pstate, erasing if necessary.
|
||||
*
|
||||
* @param serialno New iascii serial number to set in pstate.
|
||||
* @return EC_SUCCESS, or nonzero if error.
|
||||
*/
|
||||
static int flash_write_pstate_serial(const char *serialno)
|
||||
{
|
||||
int i;
|
||||
struct persist_state newpstate;
|
||||
const struct persist_state *pstate =
|
||||
(const struct persist_state *)
|
||||
flash_physical_dataptr(CONFIG_FW_PSTATE_OFF);
|
||||
|
||||
/* Check that this is OK */
|
||||
if (!serialno)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
/* Cache the old copy for read/modify/write. */
|
||||
memcpy(&newpstate, pstate, sizeof(newpstate));
|
||||
validate_pstate_struct(&newpstate);
|
||||
|
||||
/* Copy in serialno. */
|
||||
for (i = 0; i < SERIALNO_MAX - 1; i++) {
|
||||
newpstate.serialno[i] = serialno[i];
|
||||
if (serialno[i] == 0)
|
||||
break;
|
||||
}
|
||||
for (; i < SERIALNO_MAX; i++)
|
||||
newpstate.serialno[i] = 0;
|
||||
newpstate.valid_fields |= PSTATE_VALID_SERIALNO;
|
||||
|
||||
return flash_write_pstate_data(&newpstate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else /* !CONFIG_FLASH_PSTATE_BANK */
|
||||
|
||||
/**
|
||||
@@ -349,6 +453,24 @@ int flash_erase(int offset, int size)
|
||||
return flash_physical_erase(offset, size);
|
||||
}
|
||||
|
||||
const char *flash_read_serial(void)
|
||||
{
|
||||
#if defined(CONFIG_FLASH_PSTATE) && defined(CONFIG_FLASH_PSTATE_BANK)
|
||||
return flash_read_pstate_serial();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int flash_write_serial(const char *serialno)
|
||||
{
|
||||
#if defined(CONFIG_FLASH_PSTATE) && defined(CONFIG_FLASH_PSTATE_BANK)
|
||||
return flash_write_pstate_serial(serialno);
|
||||
#else
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int flash_protect_at_boot(enum flash_wp_range range)
|
||||
{
|
||||
#ifdef CONFIG_FLASH_PSTATE
|
||||
|
||||
@@ -2011,6 +2011,9 @@
|
||||
*/
|
||||
#undef CONFIG_USB_PORT_POWER_SMART_INVERTED
|
||||
|
||||
/* Support programmable USB device iSerial field. */
|
||||
#undef CONFIG_USB_SERIALNO
|
||||
|
||||
/******************************************************************************/
|
||||
/* USB port switch */
|
||||
|
||||
|
||||
@@ -245,4 +245,20 @@ uint32_t flash_get_protect(void);
|
||||
*/
|
||||
int flash_set_protect(uint32_t mask, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Get the serial number from flash.
|
||||
*
|
||||
* @return char * ascii serial number string.
|
||||
*/
|
||||
const char *flash_read_serial(void);
|
||||
|
||||
/**
|
||||
* Set the serial number in flash.
|
||||
*
|
||||
* @param serialno ascii serial number string < 30 char.
|
||||
*
|
||||
* @return success status.
|
||||
*/
|
||||
int flash_write_serial(const char *serialno);
|
||||
|
||||
#endif /* __CROS_EC_FLASH_H */
|
||||
|
||||
@@ -233,6 +233,24 @@ struct usb_setup_packet {
|
||||
WIDESTR(str) \
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_SERIALNO
|
||||
/* String Descriptor for USB, for editable strings. */
|
||||
#define USB_STRING_LEN 30
|
||||
struct usb_string_desc {
|
||||
uint8_t _len;
|
||||
uint8_t _type;
|
||||
wchar_t _data[USB_STRING_LEN];
|
||||
};
|
||||
#define USB_WR_STRING_DESC(str) \
|
||||
(&(struct usb_string_desc) { \
|
||||
/* As above, two bytes metadata, no null terminator. */ \
|
||||
sizeof(WIDESTR(str)) + 2 - 2, \
|
||||
USB_DT_STRING, \
|
||||
WIDESTR(str) \
|
||||
})
|
||||
extern struct usb_string_desc *usb_serialno_desc;
|
||||
#endif
|
||||
|
||||
/* Use these macros for declaring descriptors, to order them properly */
|
||||
#define USB_CONF_DESC(name) CONCAT2(usb_desc_, name) \
|
||||
__attribute__((section(".rodata.usb_desc_" STRINGIFY(name))))
|
||||
|
||||
Reference in New Issue
Block a user