diff --git a/src/Kconfig b/src/Kconfig index be6e7246..36cb7c12 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -50,6 +50,10 @@ config SERIAL_BAUD Specify the baud rate of the serial port. This should be set to 250000. Read the FAQ before changing this value. +config HAVE_CHIPID + bool + default n + # Generic configuration options for USB menu "USB ids" depends on USBSERIAL @@ -61,8 +65,12 @@ config USB_DEVICE_ID hex "USB device ID" default 0xabcd config USB_SERIAL_NUMBER - string "USB serial number" + string "USB serial number" if !USB_SERIAL_NUMBER_CHIPID default "12345" +config USB_SERIAL_NUMBER_CHIPID + depends on HAVE_CHIPID + bool "USB serial number from CHIPID" + default y endmenu diff --git a/src/generic/usb_cdc.c b/src/generic/usb_cdc.c index c995db49..fa1c5cb1 100644 --- a/src/generic/usb_cdc.c +++ b/src/generic/usb_cdc.c @@ -358,21 +358,34 @@ usb_req_get_descriptor(struct usb_ctrlrequest *req) { if (req->bRequestType != USB_DIR_IN) goto fail; - uint_fast8_t i; + void *desc = NULL; + uint_fast8_t flags, size, i; for (i=0; iwValue) == req->wValue && READP(d->wIndex) == req->wIndex) { - uint_fast8_t size = READP(d->size); - uint_fast8_t flags = NEED_PROGMEM ? UX_SEND_PROGMEM : UX_SEND; - if (size > req->wLength) - size = req->wLength; - else if (size < req->wLength) - flags |= UX_SEND_ZLP; - usb_do_xfer((void*)READP(d->desc), size, flags); - return; + flags = NEED_PROGMEM ? UX_SEND_PROGMEM : UX_SEND; + size = READP(d->size); + desc = (void*)READP(d->desc); } } + if (CONFIG_USB_SERIAL_NUMBER_CHIPID + && req->wValue == ((USB_DT_STRING<<8) | USB_STR_ID_SERIAL) + && req->wIndex == USB_LANGID_ENGLISH_US) { + struct usb_string_descriptor *usbserial_serialid; + usbserial_serialid = usbserial_get_serialid(); + flags = UX_SEND; + size = usbserial_serialid->bLength; + desc = (void*)usbserial_serialid; + } + if (desc) { + if (size > req->wLength) + size = req->wLength; + else if (size < req->wLength) + flags |= UX_SEND_ZLP; + usb_do_xfer(desc, size, flags); + return; + } fail: usb_do_stall(); } diff --git a/src/generic/usb_cdc.h b/src/generic/usb_cdc.h index 1763a843..279c486c 100644 --- a/src/generic/usb_cdc.h +++ b/src/generic/usb_cdc.h @@ -22,6 +22,7 @@ void usb_stall_ep0(void); void usb_set_address(uint_fast8_t addr); void usb_set_configure(void); void usb_request_bootloader(void); +struct usb_string_descriptor *usbserial_get_serialid(void); // usb_cdc.c void usb_notify_bulk_in(void); diff --git a/src/lpc176x/Kconfig b/src/lpc176x/Kconfig index 2df9419f..052396e9 100644 --- a/src/lpc176x/Kconfig +++ b/src/lpc176x/Kconfig @@ -66,4 +66,8 @@ config SERIAL bool default y +config HAVE_CHIPID + bool + default y + endif diff --git a/src/lpc176x/usbserial.c b/src/lpc176x/usbserial.c index 95ce6e74..54c28a31 100644 --- a/src/lpc176x/usbserial.c +++ b/src/lpc176x/usbserial.c @@ -13,6 +13,7 @@ #include "byteorder.h" // cpu_to_le32 #include "command.h" // DECL_CONSTANT_STR #include "generic/usb_cdc.h" // usb_notify_ep0 +#include "generic/usbstd.h" // usb_string_descriptor #include "internal.h" // gpio_peripheral #include "sched.h" // DECL_INIT #include "usb_cdc_ep.h" // USB_CDC_EP_BULK_IN @@ -34,6 +35,12 @@ #define RD_EN (1<<0) #define WR_EN (1<<1) +// IAP interface +#define IAP_LOCATION 0x1fff1ff1 +#define IAP_CMD_READ_UID 58 +#define IAP_UID_LEN 16 +typedef void (*IAP)(uint32_t *, uint32_t *); + static void usb_irq_disable(void) { @@ -104,6 +111,16 @@ sie_select_and_clear(uint32_t idx) /**************************************************************** * Interface ****************************************************************/ +#define USB_STR_SERIAL_CHIPID u"0123456789ABCDEF0123456789ABCDEF" + +#define SIZE_cdc_string_serial_chipid \ + (sizeof(cdc_string_serial_chipid) + sizeof(USB_STR_SERIAL_CHIPID) - 2) + +static struct usb_string_descriptor cdc_string_serial_chipid = { + .bLength = SIZE_cdc_string_serial_chipid, + .bDescriptorType = USB_DT_STRING, + .data = USB_STR_SERIAL_CHIPID, +}; static int_fast8_t usb_write_packet(uint32_t ep, const void *data, uint_fast8_t len) @@ -260,10 +277,36 @@ usb_request_bootloader(void) NVIC_SystemReset(); } +struct usb_string_descriptor * +usbserial_get_serialid(void) +{ + return &cdc_string_serial_chipid; +} /**************************************************************** * Setup and interrupts ****************************************************************/ +static void +usb_set_serial(void) +{ + uint32_t iap_cmd_uid[5] = {IAP_CMD_READ_UID, 0, 0, 0, 0}; + uint32_t iap_resp[5]; + + IAP iap_entry = (IAP)IAP_LOCATION; + __disable_irq(); + iap_entry(iap_cmd_uid, iap_resp); + __enable_irq(); + + uint8_t *chipid = (uint8_t *)&iap_resp[1]; + uint8_t i, j, c; + for (i = 0; i < IAP_UID_LEN; i++) { + for (j = 0; j < 2; j++) { + c = (chipid[i] >> 4*j) & 0xF; + c = (c < 10) ? '0'+c : 'A'-10+c; + cdc_string_serial_chipid.data[2*i+((j)?0:1)] = c; + } + } +} void USB_IRQHandler(void) @@ -300,6 +343,9 @@ DECL_CONSTANT_STR("RESERVE_PINS_USB", "P0.30,P0.29,P2.9"); void usbserial_init(void) { + if (CONFIG_USB_SERIAL_NUMBER_CHIPID) + usb_set_serial(); + usb_irq_disable(); // enable power enable_pclock(PCLK_USB);