altos/stmf0: Use device ID as usb serial number if requested
authorKeith Packard <keithp@keithp.com>
Mon, 15 Feb 2016 23:24:35 +0000 (15:24 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 15 Feb 2016 23:24:35 +0000 (15:24 -0800)
This exposes the hardware device ID (which is unique per-chip) as the
USB serial number, avoiding the need to create a custom ROM image for
each device.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/stmf0/ao_usb_stm.c

index b0f4c516ab151754bff7a3c8437f3bbd250e56e1..17e8709cf959095d1d089fd1a79fd909f86d2b80 100644 (file)
@@ -570,6 +570,36 @@ ao_usb_ep0_in_start(uint16_t max)
 
 static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
 
+#if AO_USB_DEVICE_ID_SERIAL
+static uint8_t ao_usb_serial[2 + 48];
+
+/* Convert a 32-bit value to 8 hexidecimal UCS2 characters */
+static void
+hex_to_ucs2(uint32_t in, uint8_t *out)
+{
+       int     i;
+
+       for (i = 28; i >= 0; i -= 4) {
+               uint8_t bits = (in >> i) & 0xf;
+               *out++ = (bits < 10) ? ('0' + bits) : ('a' + bits);
+               *out++ = 0;
+       }
+}
+
+/* Encode the device ID (96 bits) in hexidecimal to use as a device
+ * serial number
+ */
+static void
+ao_usb_serial_init(void)
+{
+       ao_usb_serial[0] = 50;  /* length */
+       ao_usb_serial[1] = AO_USB_DESC_STRING;
+       hex_to_ucs2(stm_device_id.u_id0, ao_usb_serial + 2 + 0);
+       hex_to_ucs2(stm_device_id.u_id1, ao_usb_serial + 2 + 16);
+       hex_to_ucs2(stm_device_id.u_id2, ao_usb_serial + 2 + 32);
+}
+#endif
+
 /* Walk through the list of descriptors and find a match
  */
 static void
@@ -587,6 +617,13 @@ ao_usb_get_descriptor(uint16_t value)
                                len = descriptor[2];
                        else
                                len = descriptor[0];
+#if AO_USB_DEVICE_ID_SERIAL
+                       /* Slightly hacky - the serial number is string 3 */
+                       if (type == AO_USB_DESC_STRING && (value & 0xff) == 3) {
+                               descriptor = ao_usb_serial;
+                               len = sizeof (ao_usb_serial);
+                       }
+#endif
                        ao_usb_ep0_in_set(descriptor, len);
                        break;
                }
@@ -1145,6 +1182,10 @@ ao_usb_init(void)
 
        ao_usb_enable();
 
+#if AO_USB_DEVICE_ID_SERIAL
+       ao_usb_serial_init();
+#endif
+
        debug ("ao_usb_init\n");
        ao_usb_ep0_state = AO_USB_EP0_IDLE;