From 5872753e2dbdca5b252470c5210cdf54ee1788dd Mon Sep 17 00:00:00 2001 From: laforge Date: Mon, 25 Sep 2006 21:23:52 +0000 Subject: - Include tool for Converting ASCII to UTF-16LE in C-Header - Build UTF-16LE USB String descriptors from ASCII File - Introduce USB String Descriptor to DFU and runtime firmware git-svn-id: https://svn.openpcd.org:2342/trunk@227 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- firmware/Makefile | 8 +- firmware/Makefile.dfu | 13 ++- firmware/include/usb_ch9.h | 2 +- firmware/scripts/usbstring.c | 197 ++++++++++++++++++++++++++++++++++ firmware/src/dfu/dfu.c | 51 +++++---- firmware/src/dfu/dfu.h | 12 +++ firmware/src/os/pcd_enumerate.c | 60 +++++------ firmware/src/pcd/usb_strings_app.txt | 6 ++ firmware/src/pcd/usb_strings_dfu.txt | 5 + firmware/src/picc/usb_strings_app.txt | 6 ++ firmware/src/picc/usb_strings_dfu.txt | 5 + 11 files changed, 312 insertions(+), 53 deletions(-) create mode 100644 firmware/scripts/usbstring.c create mode 100644 firmware/src/pcd/usb_strings_app.txt create mode 100644 firmware/src/pcd/usb_strings_dfu.txt create mode 100644 firmware/src/picc/usb_strings_app.txt create mode 100644 firmware/src/picc/usb_strings_dfu.txt diff --git a/firmware/Makefile b/firmware/Makefile index bc7bd8a..6dabd9a 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -190,14 +190,16 @@ endif ifeq ($(BOARD),PICC) CDEFS += -DPICC +CINCS = -Isrc/picc endif ifeq ($(BOARD),PCD) CDEFS += -DPCD +CINCS = -Isrc/pcd endif # Place -I options here -CINCS = -Iinclude -Isrc +CINCS += -Iinclude -Isrc # Place -D or -U options for ASM here ADEFS = -D$(RUN_MODE) @@ -564,11 +566,15 @@ clean_list : $(REMOVE) $(CPPSRCARM:.cpp=.d) $(REMOVE) .dep/* $(REMOVE) include/compile.h + $(REMOVE) src/picc/usb_strings_app.h .PHONY: include/compile.h include/compile.h: scripts/mkcompile_h > $@ +src/picc/usb_strings_app.h: ./scripts/usbstring src/picc/usb_strings_app.txt + cat $< | ./scripts/usbstring > $@ + # Include the dependency files. -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) diff --git a/firmware/Makefile.dfu b/firmware/Makefile.dfu index 99cd1b1..ae98f1c 100644 --- a/firmware/Makefile.dfu +++ b/firmware/Makefile.dfu @@ -69,6 +69,8 @@ PATH_TO_LINKSCRIPTS=link/ # Target file name (without extension). TARGET:=dfu +USBSTRINGS=src/picc/usb_strings_dfu.h src/pcd/usb_strings_dfu.h + # List C source files here. (C dependencies are automatically generated.) # use file-extension c for "c-only"-files SRC = @@ -161,16 +163,18 @@ endif ifeq ($(BOARD),PICC) CDEFS += -DPICC ADEFS += -DPICC +CINCS = -Isrc/picc endif ifeq ($(BOARD),PCD) SUBMDL = AT91SAM7S128 CDEFS += -DPCD ADEFS += -DPCD +CINCS = -Isrc/pcd endif # Place -I options here -CINCS = -Iinclude -Isrc +CINCS += -Iinclude -Isrc # Place -D or -U options for ASM here ADEFS += -D$(RUN_MODE) @@ -465,7 +469,7 @@ $(COBJ) : %.o : %.c $(CC) -c $(ALL_CFLAGS) $(CONLYFLAGS) $< -o $@ # Compile: create object files from C source files. ARM-only -$(COBJARM) : %.o : %.c include/compile.h +$(COBJARM) : %.o : %.c include/compile.h $(USBSTRINGS) @echo @echo $(MSG_COMPILING_ARM) $< $(CC) -c $(ALL_CFLAGS) $(CONLYFLAGS) $< -o $@ @@ -536,11 +540,16 @@ clean_list : $(REMOVE) $(CPPSRCARM:.cpp=.s) $(REMOVE) $(CPPSRCARM:.cpp=.d) $(REMOVE) .dep/* + $(REMOVE) src/picc/usb_strings_dfu.h + $(REMOVE) src/dfu/usb_strings_dfu.h .PHONY: include/compile.h include/compile.h: scripts/mkcompile_h > $@ +$(USBSTRINGS): %.h : %.txt ./scripts/usbstring + cat $< | ./scripts/usbstring > $@ + # Include the dependency files. -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) diff --git a/firmware/include/usb_ch9.h b/firmware/include/usb_ch9.h index 82edf61..46066f2 100644 --- a/firmware/include/usb_ch9.h +++ b/firmware/include/usb_ch9.h @@ -257,7 +257,7 @@ struct usb_string_descriptor { u_int8_t bLength; u_int8_t bDescriptorType; - u_int16_t wData[1]; /* UTF-16LE encoded */ + u_int16_t wData[0]; /* UTF-16LE encoded */ } __attribute__ ((packed)); /* note that "string" zero is special, it holds language codes that diff --git a/firmware/scripts/usbstring.c b/firmware/scripts/usbstring.c new file mode 100644 index 0000000..5348e66 --- /dev/null +++ b/firmware/scripts/usbstring.c @@ -0,0 +1,197 @@ +/* AT91SAM7 USB string descriptor builder + * (C) 2006 by Harald Welte + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Based on existing utf8_to_utf16le() function, + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +static int utf8_to_utf16le(const char *s, u_int16_t *cp, unsigned len) +{ + int count = 0; + u_int8_t c; + u_int16_t uchar; + + /* this insists on correct encodings, though not minimal ones. + * BUT it currently rejects legit 4-byte UTF-8 code points, + * which need surrogate pairs. (Unicode 3.1 can use them.) + */ + while (len != 0 && (c = (u_int8_t) *s++) != 0) { + if (c & 0x80) { + // 2-byte sequence: + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + if ((c & 0xe0) == 0xc0) { + uchar = (c & 0x1f) << 6; + + c = (u_int8_t) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + // 3-byte sequence (most CJKV characters): + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + } else if ((c & 0xf0) == 0xe0) { + uchar = (c & 0x0f) << 12; + + c = (u_int8_t) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c << 6; + + c = (u_int8_t) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + /* no bogus surrogates */ + if (0xd800 <= uchar && uchar <= 0xdfff) + goto fail; + + // 4-byte sequence (surrogate pairs, currently rare): + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // FIXME accept the surrogate code points (only) + + } else + goto fail; + } else + uchar = c; + + *cp++ = uchar; + count++; + len--; + } + return count; +fail: + return -1; +} + +#define COLUMNS 6 +static int print_array16(u_int16_t *buf, int len) +{ + int i; + for (i = 0; i < len; i++) { + int mod = i % COLUMNS; + char *suffix; + char *prefix; + + switch (mod) { + case 0: + if (i == 0) + prefix = "\t"; + else + prefix= "\t\t\t"; + suffix = ", "; + break; + case COLUMNS-1: + prefix = ""; + suffix = ",\n"; + break; + default: + prefix = ""; + suffix = ", "; + break; + } + + printf("%s0x%04x%s", prefix, buf[i], suffix); + } +} + +static void print_structhdr(int i, int size) +{ + printf( "static const struct {\n" + "\tstruct usb_descriptor_header hdr;\n" + "\tu_int16_t wData[];\n" + "} __attribute__((packed)) string%d = {\n" + "\t.hdr = {\n" + "\t\t.bLength = sizeof(struct usb_descriptor_header) + %u * sizeof(u_int16_t),\n" + "\t\t.bDescriptorType = USB_DT_STRING,\n" + "\t},\n" + "\t.wData = {", i, size); +} +static void print_structftr(void) +{ + printf("},\n};\n\n"); +} + +int main(int argc, char **argv) +{ + char asciibuf[512+1]; + u_int16_t utf16buf[1024+1]; + int len; + int j, i = 1; + + printf("#ifndef _USB_STRINGS_H\n#define _USB_STRINGS_H\n\n"); + printf("/* THIS FILE IS AUTOGENERATED, DO NOT MODIFY MANUALLY */\n\n"); + printf("#include \n"); + printf("#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\n\n"); + + print_structhdr(0, 1); + printf("0x0409 /* English */ "); + print_structftr(); +#if 0 + printf("static const struct usb_string_descriptor string0 = {\n" + "\t.bLength = sizeof(string0) + 1 * sizeof(u_int16_t),\n" + "\t.bDescriptorType = USB_DT_STRING,\n" + "\t.wData[0] = 0x0409, /* English */\n" + "};\n\n"); +#endif + + while (scanf("%512[^\n]\n", asciibuf) != EOF) { + len = strlen(asciibuf); + printf("/* String %u \"%s\" */\n", i, asciibuf); + + /* FIXME: check return value */ + utf8_to_utf16le(asciibuf, utf16buf, len); + + print_structhdr(i, len); +#if 0 + printf("static const struct usb_string_descriptor string%d = {\n" + "\t.bLength = sizeof(string%d) + %d * sizeof(u_int16_t),\n" + "\t.bDescriptorType = USB_DT_STRING,\n" + "\t.wData = {", i, i, len); +#endif + + print_array16(utf16buf, len); + + print_structftr(); +#if 0 + printf("},\n};\n\n"); +#endif + + i++; + } + + printf("static const struct usb_descriptor_header *usb_strings[] = {\n"); + for (j = 0; j < i; j++) + printf("\t(struct usb_descriptor_header *) &string%d,\n", j); + printf("};\n\n"); + printf("#endif /* _USB_STRINGS_H */\n"); +} diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c index 56f7ef0..40ad64f 100644 --- a/firmware/src/dfu/dfu.c +++ b/firmware/src/dfu/dfu.c @@ -26,6 +26,8 @@ #include #include +#include + #include #include #include @@ -547,11 +549,11 @@ __dfustruct const struct usb_device_descriptor dfu_dev_descriptor = { .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = 8, - .idVendor = OPENPCD_VENDOR_ID, - .idProduct = OPENPCD_PRODUCT_ID, + .idVendor = USB_VENDOR_ID, + .idProduct = USB_PRODUCT_ID, .bcdDevice = 0x0000, - .iManufacturer = 0x00, - .iProduct = 0x00, + .iManufacturer = 1, + .iProduct = 2, .iSerialNumber = 0x00, .bNumConfigurations = 0x01, }; @@ -566,7 +568,7 @@ __dfustruct const struct _dfu_desc dfu_cfg_descriptor = { USB_DT_DFU_SIZE, .bNumInterfaces = 1, .bConfigurationValue = 1, - .iConfiguration = 0, + .iConfiguration = 3, .bmAttributes = USB_CONFIG_ATT_ONE, .bMaxPower = 100, }, @@ -579,7 +581,7 @@ __dfustruct const struct _dfu_desc dfu_cfg_descriptor = { .bInterfaceClass = 0xfe, .bInterfaceSubClass = 0x01, .bInterfaceProtocol = 0x02, - .iInterface = 0, + .iInterface = 4, }, .uif[1] = { .bLength = USB_DT_INTERFACE_SIZE, @@ -590,7 +592,7 @@ __dfustruct const struct _dfu_desc dfu_cfg_descriptor = { .bInterfaceClass = 0xfe, .bInterfaceSubClass = 0x01, .bInterfaceProtocol = 0x02, - .iInterface = 0, + .iInterface = 5, }, .func_dfu = DFU_FUNC_DESC, @@ -650,37 +652,48 @@ static __dfufunc void dfu_udp_ep0_handler(void) /* Handle supported standard device request Cf Table 9-3 in USB * speciication Rev 1.1 */ switch ((bRequest << 8) | bmRequestType) { + u_int8_t desc_type, desc_index; case STD_GET_DESCRIPTOR: DEBUGE("GET_DESCRIPTOR "); - if (wValue == 0x100) { + desc_type = wValue >> 8; + desc_index = wValue & 0xff; + switch (desc_type) { + case USB_DT_DEVICE: /* Return Device Descriptor */ udp_ep0_send_data((const char *) &dfu_dev_descriptor, MIN(sizeof(dfu_dev_descriptor), wLength)); - } else if (wValue == 0x200) { + break; + case USB_DT_CONFIG: /* Return Configuration Descriptor */ udp_ep0_send_data((const char *) &dfu_cfg_descriptor, MIN(sizeof(dfu_cfg_descriptor), wLength)); -#if 0 - } else if (wValue == 0x400) { - /* Return Interface descriptor */ - if (wIndex != 0x01) + break; + case USB_DT_STRING: + /* Return String Descriptor */ + if (desc_index > ARRAY_SIZE(usb_strings)) { udp_ep0_send_stall(); - udp_ep0_send_data((const char *) - &dfu_if_descriptor, - MIN(sizeof(dfu_if_descriptor), + break; + } + DEBUGP("bLength=%u, wLength=%u\n", + usb_strings[desc_index]->bLength, wLength); + udp_ep0_send_data((const char *) usb_strings[desc_index], + MIN(usb_strings[desc_index]->bLength, wLength)); -#endif - } else if (wValue == 0x2100) { + break; + case USB_DT_CS_DEVICE: /* Return Function descriptor */ udp_ep0_send_data((const char *) &dfu_cfg_descriptor.func_dfu, MIN(sizeof(dfu_cfg_descriptor.func_dfu), wLength)); - } else + break; + default: udp_ep0_send_stall(); + break; + } break; case STD_SET_ADDRESS: DEBUGE("SET_ADDRESS "); diff --git a/firmware/src/dfu/dfu.h b/firmware/src/dfu/dfu.h index 4d53ce7..084883b 100644 --- a/firmware/src/dfu/dfu.h +++ b/firmware/src/dfu/dfu.h @@ -39,6 +39,7 @@ /* USB Interface descriptor in Runtime mode */ #define DFU_RT_IF_DESC { \ + { \ .bLength = USB_DT_INTERFACE_SIZE, \ .bDescriptorType = USB_DT_INTERFACE, \ .bInterfaceNumber = 0x01, \ @@ -48,6 +49,17 @@ .bInterfaceSubClass = 0x01, \ .bInterfaceProtocol = 0x01, \ .iInterface = 1, \ + }, { \ + .bLength = USB_DT_INTERFACE_SIZE, \ + .bDescriptorType = USB_DT_INTERFACE, \ + .bInterfaceNumber = 0x02, \ + .bAlternateSetting = 0x00, \ + .bNumEndpoints = 0x00, \ + .bInterfaceClass = 0xfe, \ + .bInterfaceSubClass = 0x01, \ + .bInterfaceProtocol = 0x01, \ + .iInterface = 2, \ + }, \ } #define __dfufunctab __attribute__ ((section (".dfu.functab"))) diff --git a/firmware/src/os/pcd_enumerate.c b/firmware/src/os/pcd_enumerate.c index 63fe608..588831c 100644 --- a/firmware/src/os/pcd_enumerate.c +++ b/firmware/src/os/pcd_enumerate.c @@ -34,6 +34,8 @@ #include #include +#include + #include #include #include @@ -89,8 +91,8 @@ const struct usb_device_descriptor dev_descriptor = { .idVendor = USB_VENDOR_ID, .idProduct = USB_PRODUCT_ID, .bcdDevice = 0x0000, - .iManufacturer = 0x00, - .iProduct = 0x00, + .iManufacturer = 3, + .iProduct = 4, .iSerialNumber = 0x00, .bNumConfigurations = 0x01, }; @@ -100,8 +102,7 @@ struct _desc { struct usb_interface_descriptor uif; struct usb_endpoint_descriptor ep[3]; #ifdef CONFIG_DFU - struct usb_interface_descriptor uif_dfu; - struct usb_dfu_func_descriptor func_dfu; + struct usb_interface_descriptor uif_dfu[2]; #endif }; @@ -111,17 +112,16 @@ const struct _desc cfg_descriptor = { .bDescriptorType = USB_DT_CONFIG, .wTotalLength = USB_DT_CONFIG_SIZE + #ifdef CONFIG_DFU - 2 * USB_DT_INTERFACE_SIZE + - 3 * USB_DT_ENDPOINT_SIZE + - USB_DT_DFU_SIZE, - .bNumInterfaces = 2, + 3 * USB_DT_INTERFACE_SIZE + + 3 * USB_DT_ENDPOINT_SIZE, + .bNumInterfaces = 3, #else 1 * USB_DT_INTERFACE_SIZE + 3 * USB_DT_ENDPOINT_SIZE, .bNumInterfaces = 1, #endif .bConfigurationValue = 1, - .iConfiguration = 0, + .iConfiguration = 5, .bmAttributes = USB_CONFIG_ATT_ONE, .bMaxPower = 100, /* 200mA */ }, @@ -134,7 +134,7 @@ const struct _desc cfg_descriptor = { .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0xff, - .iInterface = 0, + .iInterface = 6, }, .ep= { { @@ -162,16 +162,9 @@ const struct _desc cfg_descriptor = { }, #ifdef CONFIG_DFU .uif_dfu = DFU_RT_IF_DESC, - .func_dfu = DFU_FUNC_DESC, #endif }; -static const struct usb_string_descriptor string0 = { - .bLength = sizeof(string0), - .bDescriptorType = USB_DT_STRING, - .wData[0] = 0x0409, /* English */ -}; - struct epstate { u_int32_t state_busy; u_int32_t state_pending; @@ -568,9 +561,13 @@ static void udp_ep0_handler(void) /* Handle supported standard device request Cf Table 9-3 in USB * speciication Rev 1.1 */ switch ((bRequest << 8) | bmRequestType) { + u_int8_t desc_type, desc_index; case STD_GET_DESCRIPTOR: DEBUGE("GET_DESCRIPTOR "); - if (wValue == 0x100) { + desc_type = wValue >> 8; + desc_index = wValue & 0xff; + switch (desc_type) { + case USB_DT_DEVICE: /* Return Device Descriptor */ #ifdef CONFIG_DFU if (*dfu->dfu_state != DFU_STATE_appIDLE) @@ -582,7 +579,8 @@ static void udp_ep0_handler(void) #endif udp_ep0_send_data((const char *) &dev_descriptor, MIN(sizeof(dev_descriptor), wLength)); - } else if (wValue == 0x200) { + break; + case USB_DT_CONFIG: /* Return Configuration Descriptor */ #ifdef CONFIG_DFU if (*dfu->dfu_state != DFU_STATE_appIDLE) @@ -594,19 +592,20 @@ static void udp_ep0_handler(void) #endif udp_ep0_send_data((const char *) &cfg_descriptor, MIN(sizeof(cfg_descriptor), wLength)); - } else if (wValue == 0x300) { + break; + case USB_DT_STRING: /* Return String descriptor */ - switch (wIndex) { - case 0: - udp_ep0_send_data((const char *) &string0, - MIN(sizeof(string0), wLength)); - break; - default: - /* FIXME: implement this */ + if (desc_index > ARRAY_SIZE(usb_strings)) { udp_ep0_send_stall(); break; } - } else if (wValue == 0x2100) { + DEBUGP("bLength=%u, wLength=%u\n", + usb_strings[desc_index]->bLength, wLength); + udp_ep0_send_data((const char *) usb_strings[desc_index], + MIN(usb_strings[desc_index]->bLength, + wLength)); + break; + case USB_DT_CS_DEVICE: /* Return Function descriptor */ udp_ep0_send_data((const char *) &dfu->dfu_cfg_descriptor->func_dfu, MIN(sizeof(dfu->dfu_cfg_descriptor->func_dfu), wLength)); @@ -620,8 +619,10 @@ static void udp_ep0_handler(void) MIN(sizeof(dfu_if_descriptor), wLength)); #endif - } else + break; + default: udp_ep0_send_stall(); + } break; case STD_SET_ADDRESS: DEBUGE("SET_ADDRESS "); @@ -710,7 +711,6 @@ static void udp_ep0_handler(void) DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f); wIndex &= 0x0F; if ((wValue == 0) && wIndex && (wIndex <= 3)) { - struct req_ctx *rctx; reset_ep(wIndex); udp_ep0_send_zlp(); } else diff --git a/firmware/src/pcd/usb_strings_app.txt b/firmware/src/pcd/usb_strings_app.txt new file mode 100644 index 0000000..9180fbc --- /dev/null +++ b/firmware/src/pcd/usb_strings_app.txt @@ -0,0 +1,6 @@ +OpenPCD DFU Interface - Application Partition +OpenPCD DFU Interface - Bootloader Partition +bitmanufaktur.de IT Solutions and hmw-consulting.de +OpenPCD RFID Simulator - Runtime Mode +OpenPCD Runtime Configuration +OpenPCD Runtime Interface diff --git a/firmware/src/pcd/usb_strings_dfu.txt b/firmware/src/pcd/usb_strings_dfu.txt new file mode 100644 index 0000000..40b7e27 --- /dev/null +++ b/firmware/src/pcd/usb_strings_dfu.txt @@ -0,0 +1,5 @@ +bitmanufaktur.de IT Solutions and hmw-consulting.de +OpenPCD RFID Simulator - DFU Mode +OpenPCD DFU Configuration +OpenPCD DFU Interface - Application Partition +OpenPCD DFU Interface - Bootloader Partition diff --git a/firmware/src/picc/usb_strings_app.txt b/firmware/src/picc/usb_strings_app.txt new file mode 100644 index 0000000..ea08dab --- /dev/null +++ b/firmware/src/picc/usb_strings_app.txt @@ -0,0 +1,6 @@ +OpenPICC DFU Interface - Application Partition +OpenPICC DFU Interface - Bootloader Partition +bitmanufaktur.de IT Solutions and hmw-consulting.de +OpenPICC RFID Simulator - Runtime Mode +OpenPIIC Runtime Configuration +OpenPICC Runtime Interface diff --git a/firmware/src/picc/usb_strings_dfu.txt b/firmware/src/picc/usb_strings_dfu.txt new file mode 100644 index 0000000..681c30a --- /dev/null +++ b/firmware/src/picc/usb_strings_dfu.txt @@ -0,0 +1,5 @@ +bitmanufaktur.de IT Solutions and hmw-consulting.de +OpenPICC RFID Simulator - DFU Mode +OpenPIIC DFU Configuration +OpenPICC DFU Interface - Application Partition +OpenPICC DFU Interface - Bootloader Partition -- cgit v1.2.3