diff --git a/src/.gdbinit b/src/.gdbinit new file mode 100644 index 0000000..3415b26 --- /dev/null +++ b/src/.gdbinit @@ -0,0 +1,4 @@ +set arm force-mode thumb +set arm fallback-mode thumb +target remote localhost:3333 +monitor reset halt diff --git a/src/Makefile b/src/Makefile index 34bd64b..d571251 100644 --- a/src/Makefile +++ b/src/Makefile @@ -50,10 +50,10 @@ endif # # Define project name here -PROJECT = gpgtoken +PROJECT = gnuk # Define linker script file here -LDSCRIPT= gpgtoken.ld +LDSCRIPT= gnuk.ld # Imported source files CHIBIOS = ../ChibiOS_2.0.2 @@ -78,7 +78,7 @@ CSRC = $(PORTSRC) \ $(CHIBIOS)/os/various/syscalls.c \ $(STMUSBSRC) \ $(USBCDCSRC) \ - main.c hw_config.c usb_lld.c + main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c # List ASM source files here ASMSRC = $(PORTASM) \ diff --git a/src/gpgtoken.ld b/src/gnuk.ld similarity index 100% rename from src/gpgtoken.ld rename to src/gnuk.ld diff --git a/src/gpg.c b/src/gpg.c new file mode 100644 index 0000000..73ae2d5 --- /dev/null +++ b/src/gpg.c @@ -0,0 +1,570 @@ +/* + * gpg.c -- + * + * Copyright (C) 2010 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Gnuk, a GnuPG USB Token implementation. + * + * Gnuk 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 3 of the License, or + * (at your option) any later version. + * + * Gnuk 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, see . + * + */ + +#define RSA_SIGNATURE_LENGTH 128 /* 128 byte == 1024-bit */ +extern unsigned char *rsa_sign (unsigned char *); + +#define INS_PUT_DATA 0xDA +#define INS_VERIFY 0x20 +#define INS_GET_DATA 0xCA +#define INS_GET_RESPONSE 0xC0 +#define INS_SELECT_FILE 0xA4 +#define INS_READ_BINARY 0xB0 +#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 +#define INS_PSO 0x2A + +static const char const select_file_TOP_result[] = + { 0x00, 0x00, 0x0b, 0x10, 0x3f, 0x00, 0x38, 0xff, 0xff, 0x44, + 0x44, 0x01, 0x05, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 }; + +static const char const get_data_64_result[] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +static const char const get_data_5e_result[] = + { /* Login Data */ + 'g', 'n', 'i', 'i', 'b', 'e' + }; + +/***** do_65 is compound object of { do_47, do_4f, do_c0,..,c6,cd }*/ +const unsigned char const do_6e_head[] = + { + 0x6e, 0x81, 2*10+3+16+1+1+1+1+7+60+60+12 /* (> 128) */ + }; + +const char const do_47[] = /* Card Capabilities */ + { + 0x47, 3, + 0x00 /*???*/, 0x00 /*???*/, 0x00 /*???*/ + /* XXX: See ISO 7816-4 for first byte and second byte */ + }; + +const char const do_4f[] = /* AID */ + { + 0x4f, 16, + 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01, + 0x01, 0x01, /* Version 1.1 */ + 0xF5, 0x17, /* Manufacturer (FSIJ) */ + 0x00, 0x00, 0x00, 0x02, /* Serial */ + 0x00, 0x00 + }; + +const char const do_c0[] = + { /* Extended capability */ + 0xc0, 1, + 0x00 + }; + +const char const do_c1[] = + { /* Algorithm Attributes Signature ??? */ + 0xc1, 1, + 0x01, /* RSA */ /*??? should have length modulus, length exponent ??? */ + }; + +const char const do_c2[] = + { /* Algorithm Attributes Decryption ??? */ + 0xc2, 1, + 0x00 + }; + +const char const do_c3[] = + { /* Algorithm Attributes Authentication ??? */ + 0xc3, 1, + 0x00 + }; + +const char const do_c4[] = + { /* CHV status bytes */ + 0xc4, 7, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01 + }; + +const char const do_c5[] = + { + 0xc5, 60, + /* sign */ + 0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d, + 0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc, + 0xe5, 0x02, 0xbf, 0xcd, + /* enc */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* auth */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + +const char const do_c6[] = /* CA Fingerprints */ + { + 0xc6, 60, + /* c6 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* c7 */ + 0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d, + 0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc, + 0xe5, 0x02, 0xbf, 0xcd, + /* c8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + +const char const do_cd[] = + { /* Generation time */ + 0xcd, 12, + 0x00, 0x00, 0x00, 0x00, + 0x49, 0x8a, 0x50, 0x7a, /* 0xce */ + 0x00, 0x00, 0x00, 0x00, + }; +/*************************/ + +/***** do_65 is compound object of { do_5b, do_5f2d, do_5f35 }*/ +const char const do_65_head[] = + { + 0x65, 2*1+3*2+12+2+1 + }; + +const char const do_5b[] = + { + 0x5b, 12, + 'N', 'I', 'I', 'B', 'E', ' ', 'Y', 'u', 't', 'a', 'k', 'a' + }; + +const char const do_5f2d[] = + { + 0x5f, 0x2d, 2, + 'j', 'a' + }; + +const char const do_5f35[] = + { + 0x5f, 0x35, 1, + '1' + }; +/****************************/ + +/* do_7a is compound object of { do_93 } */ +const char const do_7a_head[] = + { + 0x7a, 2+3 + }; + +/* Digital Signature Counter (3-bytes) */ +const char const do_93[] = + { + 0x93, 3, + 0, 0, 0 + }; +/****************************/ + + +const char const do_5f50[] = + { + 0x5f, 0x50, 20, + 'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w', + '.', 'f', 's', 'i', 'j', '.', 'o', 'r', 'g', '/' + }; + + +/* + * 73 + * 101 + * 102 + * 103 + * 104 + * + * 65 - 5b, 5f2d, 5f35 + * 6e - 47, 4f, c0, c1, c2, c3, c4, c5, c6, cd + * 7a - 93 + * + * + * 65 L-65 [5b L-5b .... ] [5f2d 2 'j' 'a'] [5f35 1 '1'] + * 6e L-6e [47 3 x x x ] [4f L-4f ...] [c0 L-c0 ...] ... + * 7a L-7a [93 L-93 ... ] + */ + +static byte +process_command_adpu (void) +{ + if (icc_read_buf[1] == INS_GET_RESPONSE) + { + stx_put_string (" - GET Response\r\n"); + + if ((icc_result_flag & ICC_RESULT_BUF)) + return 0; + else + { + stx_put_string ("Wrong GET Response\r\n"); + return 1; + } + } + + icc_result_flag = 0; + + /* +INS_VERIFY + + 00 20 00 81 06 - ??? + CHV1 + 00 20 00 82 06 - ??? + CHV2 + 00 20 00 83 08 - ??? + CHV3 + */ + + if (icc_read_buf[1] == INS_PUT_DATA) + { + stx_put_string (" - PUT DATA\r\n"); + icc_result_value = 0x9000; /* 6a88: No record */ + icc_result_len = 0; + icc_result_flag = 0; + return 0; + } + + if (icc_read_buf[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR) + { + stx_put_string (" - Generate Asymmetric Key Pair\r\n"); + + if (icc_read_buf[2] == 0x81) + { + /* + * tag: 0x7f49 public key data + * tag: 0x0081 RSA modulus + * tag: 0x0082 RSA exponent + * + * TAG + * [0x7f 0x49][LEN][DATA] + * _______/ \_________________ + * / \ + * [0x81][128][DATA][0x82][3][DATA] + * __/ \__ 0x01, 0x00, 0x01 + * / \ + * 0x81 0x80 + */ + + if (icc_read_buf[6] == 0x00 && icc_read_buf[5] == 0xb6) + { /* Key for Sign */ + static const char const get_data_sigkey_result[] = + { + 0x7f, 0x49, 0x81, 0x88, + 0x81, 0x81, 0x80, + /* 128-byte data */ + /* modulus */ + 0xdb, 0xca, 0x58, 0x74, 0x44, 0x8e, 0x1a, 0x2c, + 0xa0, 0x91, 0xac, 0xc4, 0xe2, 0x77, 0x2b, 0x90, + 0xcf, 0x3c, 0x7e, 0x81, 0xdc, 0x8d, 0xb0, 0xe2, + 0xf1, 0xfe, 0x56, 0x7e, 0x54, 0x57, 0xf0, 0xd8, + 0xb1, 0xb1, 0xaa, 0x9d, 0x8f, 0xb0, 0x56, 0x01, + 0xaa, 0x6b, 0xa7, 0x2e, 0xce, 0x01, 0x20, 0xd2, + 0xf8, 0xf5, 0x85, 0x3a, 0xc2, 0x73, 0xf9, 0x66, + 0x30, 0x28, 0x65, 0x5e, 0x3f, 0x91, 0xaf, 0x3f, + 0xf6, 0x1c, 0x31, 0x2f, 0xa2, 0x91, 0xbb, 0x41, + 0x91, 0x41, 0x08, 0x0a, 0xc5, 0x3e, 0x39, 0xda, + 0x2f, 0x6f, 0x58, 0x51, 0xe2, 0xd2, 0xe9, 0x42, + 0x8a, 0x7b, 0x72, 0x7b, 0x15, 0xf6, 0xf6, 0x6a, + 0x12, 0x6e, 0x0c, 0x15, 0x24, 0x13, 0x16, 0x55, + 0x3a, 0xf1, 0xa7, 0x16, 0x3e, 0xe9, 0xc8, 0x3d, + 0x2c, 0x3d, 0xae, 0x51, 0x2d, 0x7f, 0xef, 0x92, + 0x25, 0x6a, 0xbb, 0x02, 0x03, 0x70, 0x45, 0x3d, + /* public exponent */ + 0x82, 3, 0x01, 0x00, 0x01 + }; + + icc_result_value = get_data_sigkey_result; + icc_result_len = sizeof (get_data_sigkey_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + } + else if (icc_read_buf[6] == 0x00 && icc_read_buf[5] == 0xb8) + { /* Key for Encryption */ + static const char const get_data_enckey_result[] = + { + 0x7f, 0x49, 0x81, 0x88, + 0x81, 0x81, 0x80, + /* 128-byte data */ + 0xB2, 0x19, 0x91, 0x42, 0x27, 0xC7, 0x97, 0xFE, + 0x92, 0x64, 0x42, 0xCA, 0xE3, 0x66, 0x4D, 0xD0, + 0x31, 0xE4, 0x10, 0x31, 0x0F, 0xC7, 0x07, 0x4A, + 0xAA, 0x6D, 0x31, 0xA2, 0x88, 0x68, 0xAF, 0x45, + 0x8E, 0x42, 0x12, 0xFF, 0xB6, 0xEF, 0x6E, 0x54, + 0x7E, 0x51, 0x8E, 0xBC, 0xE8, 0x18, 0x79, 0xA7, + 0xBC, 0xA8, 0x14, 0x8B, 0xE7, 0x91, 0x57, 0x38, + 0xCE, 0x4F, 0x6E, 0x16, 0x48, 0xCB, 0xD6, 0x0B, + 0x3A, 0x53, 0x70, 0xF3, 0xFC, 0xFA, 0xC3, 0x58, + 0x3D, 0xE7, 0x2A, 0x5E, 0xDD, 0xE1, 0x38, 0x82, + 0x57, 0x87, 0x3A, 0xDC, 0x34, 0xDE, 0xCD, 0x5D, + 0x33, 0x1C, 0xAB, 0xB0, 0x1B, 0xEE, 0x82, 0x43, + 0x7B, 0xAC, 0xF8, 0xF0, 0xB2, 0x62, 0xB2, 0x6D, + 0x09, 0xED, 0x2E, 0xD1, 0xBA, 0xB8, 0xC6, 0x96, + 0xFA, 0x3E, 0xB4, 0xE3, 0xFE, 0x68, 0xF9, 0x51, + 0x9A, 0x8C, 0x8B, 0x20, 0x93, 0xD0, 0x2E, 0x0F, + 0x82, 3, 0x01, 0x00, 0x01 + }; + + icc_result_value = get_data_enckey_result; + icc_result_len = sizeof (get_data_enckey_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + } + /* icc_read_buf[5] == 0xa4 */ + else + { + icc_result_value = 0x6a88; /* No record */ + icc_result_len = 0; + icc_result_flag = 0; + } + } + else + { + icc_result_value = 0x6a88; /* No record */ + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[1] == INS_READ_BINARY) + { /* it must be for DF 0x2f02 */ + stx_put_string (" - Read binary\r\n"); + + if (icc_read_buf[3] >= 6) + { + icc_result_value = 0x6b00; /* BAD_P0_P1 */ + icc_result_len = 0; + icc_result_flag = 0; + } + else + { /* Tag 5a, serial number */ + static const char const get_data_rb_result[] = { 0x5a, 0x4, 0x01, 0x02, 0x03, 0x04 }; + + icc_result_value = (word)get_data_rb_result; + icc_result_len = sizeof (get_data_rb_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + + /* XXX: Next get response returns 6282??? eof_reached ??? */ + } + } + else if (icc_read_buf[1] == INS_SELECT_FILE) + { + if (icc_read_buf[2] == 4) /* Selection by DF name */ + { + stx_put_string (" - select DF by name\r\n"); + /* + * XXX: Should return contents. + */ + + if (1) + { + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[4] == 2 + && icc_read_buf[5] == 0x2f + && icc_read_buf[6] == 02) + { + stx_put_string (" - select 0x2f02 EF\r\n"); + /* + * MF.EF-GDO -- Serial number of the card and name of the owner + */ + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + else + if (icc_read_buf[4] == 2 + && icc_read_buf[5] == 0x3f + && icc_read_buf[6] == 0) + { + stx_put_string (" - select ROOT MF\r\n"); + if (icc_read_buf[3] == 0x0c) + { + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + else + { + icc_result_value = select_file_TOP_result; + icc_result_len = sizeof (select_file_TOP_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + } + } + else + { + stx_put_string (" - select ?? \r\n"); + + icc_result_value = 0x6a82; /* File missing */ + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[1] == INS_GET_DATA) + { + stx_put_string (" - Get Data\r\n"); + + switch (((icc_read_buf[2]<<8) | icc_read_buf[3])) + { + case 0x4f: /* AID */ + { + icc_result_value = (word)&do_4f[2]; + icc_result_len = sizeof (do_4f) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5e: /* Login data */ + { + icc_result_value = (word)get_data_5e_result; + icc_result_len = sizeof (get_data_5e_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x64: + { + icc_result_value = (word)get_data_64_result; + icc_result_len = sizeof (get_data_64_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc0: + { + icc_result_value = (word)&do_c0[2]; + icc_result_len = sizeof (do_c0) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc4: + { + icc_result_value = (word)&do_c4[2]; + icc_result_len = sizeof (do_c4) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5b: /* Name */ + { + icc_result_value = (word)&do_5b[2]; + icc_result_len = sizeof (do_5b) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x93: /* Digital Signature Counter (3-bytes) */ + { + icc_result_value = (word)&do_93[2]; + icc_result_len = sizeof (do_93) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc5: /* Fingerprints */ + { + icc_result_value = &do_c5[2]; + icc_result_len = sizeof (do_c5) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5f2d: /* Language preference */ + { + icc_result_value = (word)&do_5f2d[3]; + icc_result_len = sizeof (do_5f2d) - 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5f35: /* Sex */ + { + icc_result_value = (word)&do_5f35[3]; + icc_result_len = sizeof (do_5f35) - 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5f50: /* URL */ + { + icc_result_value = (word)&do_5f50[3]; + icc_result_len = sizeof (do_5f50) - 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x65: /* Card Holder Related Data (Tag) */ + { + icc_result_value = (word)do_65_head; + icc_result_len = do_65_head[1] + 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x6e: /* Application Related Data (Tag) */ + { + icc_result_value = (word)do_6e_head; + icc_result_len = do_6e_head[2] + 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x7a: /* Security Support Template (Tag) */ + { + icc_result_value = (word)do_7a_head; + icc_result_len = do_7a_head[1] + 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc6: /* List of CA fingerprints */ + case 0xcd: /* List of generation dates/times public-key pairs */ + default: + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[1] == INS_PSO) + { + stx_put_string (" - PSO\r\n"); + + if (icc_read_buf[2] == 0x9E && icc_read_buf[3] == 0x9A) + { + if (icc_read_len != 5 + 35 && icc_read_len != 5 + 35 + 1) + stx_put_string (" wrong length\r\n"); + else + { + icc_result_value = rsa_sign (&icc_read_buf[5]); + icc_result_len = RSA_SIGNATURE_LENGTH; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_RAM; + } + + stx_put_string ("done.\r\n"); + } + else + { + stx_put_string (" - ???\r\n"); + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + } + else + { + stx_put_string (" - ???\r\n"); + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + + return 0; +} diff --git a/src/hw_config.c b/src/hw_config.c new file mode 100644 index 0000000..c0153c0 --- /dev/null +++ b/src/hw_config.c @@ -0,0 +1,40 @@ +#include "ch.h" +#include "hal.h" + +#include "usb_lib.h" +#include "usb_prop.h" +#include "usb_desc.h" +#include "hw_config.h" +#include "platform_config.h" +#include "usb_pwr.h" + +void +Enter_LowPowerMode (void) +{ + bDeviceState = SUSPENDED; +} + +void +Leave_LowPowerMode (void) +{ + DEVICE_INFO *pInfo = &Device_Info; + + if (pInfo->Current_Configuration != 0) + bDeviceState = CONFIGURED; + else + bDeviceState = ATTACHED; +} + +void +USB_Cable_Config (FunctionalState NewState) +{ + if (NewState != DISABLE) + palClearPad (IOPORT3, GPIOC_DISC); + else + palSetPad (IOPORT3, GPIOC_DISC); +} + +void +Get_SerialNum (void) +{ +} diff --git a/src/icc.c b/src/icc.c new file mode 100644 index 0000000..8768ee8 --- /dev/null +++ b/src/icc.c @@ -0,0 +1,886 @@ +/* + * icc.c -- + * + * Copyright (C) 2010 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Gnuk, a GnuPG USB Token implementation. + * + * Gnuk 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 3 of the License, or + * (at your option) any later version. + * + * Gnuk 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, see . + * + */ + +enum icc_state { + ICC_STATE_INITIAL, + ICC_STATE_WAITING_ADPU, + ICC_STATE_BUSY1, + ICC_STATE_BUSY2, + ICC_STATE_BUSY3, + ICC_STATE_BUSY4, + ICC_STATE_BUSY5, + ICC_STATE_ADPU_RECEIVED_PARTIALLY, + ICC_STATE_ADPU_SENT_PARTIALLY, +}; + +#define RSA_SIGNATURE_LENGTH 128 /* 128 byte == 1024-bit */ +extern unsigned char *rsa_sign (unsigned char *); + +/* Three callbacks */ + +static byte icc_cycle; +byte icc_status; + +/* GET_ICC_STATUS */ +byte +icc_get_status (void) +{ +#if 0 + if (icc_status == ICC_STATUS_BUSY) + return ((icc_cycle++) & 0x0f) | ICC_STATUS_BUSY; +#endif + + return icc_status; +} + +/* XXX: need to be fixed... *//* T=0 */ +const char *ATR = "\x3B\x02\xbe\xef"; + +task_t icc_wait_task; +byte icc_wait_result; + + +/* ICC_POWER_ON */ +const byte * +icc_power_on (void) +{ + task_t t = icc_wait_task; + + if (t != 0) + { + icc_wait_task = 0; + need_resched = 1; + icc_wait_result = 1; + stx_wakeup (t); + } + + return ATR; +} + +word icc_initial_sp; +void icc_main (void); +extern word task[]; + +extern byte icc_write_buf[2]; +byte icc_read_buf[143]; +extern int icc_write_len; +extern int icc_read_len; + +extern task_t icc_write_task; +extern task_t icc_read_task; + +/* ICC_POWER_OFF */ +void +icc_power_off (void) +{ +#if 0 + if (icc_read_task) + { + icc_read_task = 0; + icc_read_len = 0xff; + } + + if (icc_write_task) + { + icc_write_task = 0; + icc_write_len = 0xff; + } + + if (icc_wait_task) + { + icc_wait_task = 0; + icc_wait_result = 0; + } + + icc_status = ICC_STATUS_BUSY; + stx_wakeup (ICC_TASK); +#endif +#if 1 + extern stx_cancel_write (byte); + word sp = icc_initial_sp; + + if (sp) + { + icc_status = ICC_STATUS_BUSY; + + stx_cancel_write (ICC_TASK); + + /* Push PC */ + *(byte *)(sp - 1) = ((word)icc_main >> 8); + *(byte *)sp = ((word)icc_main & 0xff); + sp -= 32 + 1 + 2; /* Registers 0-31, SREG and PC */ + + need_resched = 1; + task[ICC_TASK] = sp; + stx_wakeup (ICC_TASK); + } +#endif +} + +#define INS_PUT_DATA 0xDA +#define INS_VERIFY 0x20 +#define INS_GET_DATA 0xCA +#define INS_GET_RESPONSE 0xC0 +#define INS_SELECT_FILE 0xA4 +#define INS_READ_BINARY 0xB0 +#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 +#define INS_PSO 0x2A + +extern byte *icc_read_p; + +word icc_result_value; /* Buffer pointer or status word */ +byte icc_result_flag; +byte icc_result_len; + +#define ICC_RESULT_BUF 0x80 +#define ICC_RESULT_BUF_MASK 0x7f +#define ICC_RESULT_BUF_ROM 0 +#define ICC_RESULT_BUF_EEPROM 1 +#define ICC_RESULT_BUF_RAM 2 +/************************ 3 */ + +static void +icc_success (void) +{ + icc_result_flag = 0; +} + +byte +stx_icc_read (void) +{ + asm volatile ("cli"); + icc_read_p = icc_read_buf; + icc_read_len = 0; + icc_read_task = current; + task_wait_bits |= taskset_current (); + icc_status = ICC_STATUS_READY; + stx_yield (); + + if (icc_read_len == 5 + && (icc_read_buf[1] == INS_SELECT_FILE + || icc_read_buf[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR + || icc_read_buf[1] == INS_PUT_DATA + || icc_read_buf[1] == INS_VERIFY + || icc_read_buf[1] == INS_PSO)) + { /* Recieve a packet again */ + asm volatile ("cli"); + icc_read_task = current; + task_wait_bits |= taskset_current (); + icc_status = ICC_STATUS_DATA; + stx_yield (); + } + + return icc_read_len; +} + +static byte +receive_command_adpu (void) +{ + byte r; + char s[11]; + + if ((r = stx_icc_read ()) != 0xff) + { + int i; + + for (i = 0; i < icc_read_len; i++) + { + sprintf (s, " %02x", icc_read_buf[i]); + stx_put_string (s); + } + } + + return r; +} + +static const char const select_file_TOP_result[] = + { 0x00, 0x00, 0x0b, 0x10, 0x3f, 0x00, 0x38, 0xff, 0xff, 0x44, + 0x44, 0x01, 0x05, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 }; + +static const char const get_data_64_result[] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +static const char const get_data_5e_result[] = + { /* Login Data */ + 'g', 'n', 'i', 'i', 'b', 'e' + }; + +/***** do_65 is compound object of { do_47, do_4f, do_c0,..,c6,cd }*/ +const unsigned char const do_6e_head[] = + { + 0x6e, 0x81, 2*10+3+16+1+1+1+1+7+60+60+12 /* (> 128) */ + }; + +const char const do_47[] = /* Card Capabilities */ + { + 0x47, 3, + 0x00 /*???*/, 0x00 /*???*/, 0x00 /*???*/ + /* XXX: See ISO 7816-4 for first byte and second byte */ + }; + +const char const do_4f[] = /* AID */ + { + 0x4f, 16, + 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01, + 0x01, 0x01, /* Version 1.1 */ + 0xF5, 0x17, /* Manufacturer (FSIJ) */ + 0x00, 0x00, 0x00, 0x02, /* Serial */ + 0x00, 0x00 + }; + +const char const do_c0[] = + { /* Extended capability */ + 0xc0, 1, + 0x00 + }; + +const char const do_c1[] = + { /* Algorithm Attributes Signature ??? */ + 0xc1, 1, + 0x01, /* RSA */ /*??? should have length modulus, length exponent ??? */ + }; + +const char const do_c2[] = + { /* Algorithm Attributes Decryption ??? */ + 0xc2, 1, + 0x00 + }; + +const char const do_c3[] = + { /* Algorithm Attributes Authentication ??? */ + 0xc3, 1, + 0x00 + }; + +const char const do_c4[] = + { /* CHV status bytes */ + 0xc4, 7, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01 + }; + +const char const do_c5[] = + { + 0xc5, 60, + /* sign */ + 0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d, + 0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc, + 0xe5, 0x02, 0xbf, 0xcd, + /* enc */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* auth */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + +const char const do_c6[] = /* CA Fingerprints */ + { + 0xc6, 60, + /* c6 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* c7 */ + 0x5b, 0x85, 0x67, 0x3c, 0x08, 0x4f, 0x80, 0x0d, + 0x54, 0xac, 0x95, 0x1c, 0x35, 0x15, 0x97, 0xcc, + 0xe5, 0x02, 0xbf, 0xcd, + /* c8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + +const char const do_cd[] = + { /* Generation time */ + 0xcd, 12, + 0x00, 0x00, 0x00, 0x00, + 0x49, 0x8a, 0x50, 0x7a, /* 0xce */ + 0x00, 0x00, 0x00, 0x00, + }; +/*************************/ + +/***** do_65 is compound object of { do_5b, do_5f2d, do_5f35 }*/ +const char const do_65_head[] = + { + 0x65, 2*1+3*2+12+2+1 + }; + +const char const do_5b[] = + { + 0x5b, 12, + 'N', 'I', 'I', 'B', 'E', ' ', 'Y', 'u', 't', 'a', 'k', 'a' + }; + +const char const do_5f2d[] = + { + 0x5f, 0x2d, 2, + 'j', 'a' + }; + +const char const do_5f35[] = + { + 0x5f, 0x35, 1, + '1' + }; +/****************************/ + +/* do_7a is compound object of { do_93 } */ +const char const do_7a_head[] = + { + 0x7a, 2+3 + }; + +/* Digital Signature Counter (3-bytes) */ +const char const do_93[] = + { + 0x93, 3, + 0, 0, 0 + }; +/****************************/ + + +const char const do_5f50[] = + { + 0x5f, 0x50, 20, + 'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w', + '.', 'f', 's', 'i', 'j', '.', 'o', 'r', 'g', '/' + }; + + +/* + * 73 + * 101 + * 102 + * 103 + * 104 + * + * 65 - 5b, 5f2d, 5f35 + * 6e - 47, 4f, c0, c1, c2, c3, c4, c5, c6, cd + * 7a - 93 + * + * + * 65 L-65 [5b L-5b .... ] [5f2d 2 'j' 'a'] [5f35 1 '1'] + * 6e L-6e [47 3 x x x ] [4f L-4f ...] [c0 L-c0 ...] ... + * 7a L-7a [93 L-93 ... ] + */ + +static byte +process_command_adpu (void) +{ + if (icc_read_buf[1] == INS_GET_RESPONSE) + { + stx_put_string (" - GET Response\r\n"); + + if ((icc_result_flag & ICC_RESULT_BUF)) + return 0; + else + { + stx_put_string ("Wrong GET Response\r\n"); + return 1; + } + } + + icc_result_flag = 0; + + /* +INS_VERIFY + + 00 20 00 81 06 - ??? + CHV1 + 00 20 00 82 06 - ??? + CHV2 + 00 20 00 83 08 - ??? + CHV3 + */ + + if (icc_read_buf[1] == INS_PUT_DATA) + { + stx_put_string (" - PUT DATA\r\n"); + icc_result_value = 0x9000; /* 6a88: No record */ + icc_result_len = 0; + icc_result_flag = 0; + return 0; + } + + if (icc_read_buf[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR) + { + stx_put_string (" - Generate Asymmetric Key Pair\r\n"); + + if (icc_read_buf[2] == 0x81) + { + /* + * tag: 0x7f49 public key data + * tag: 0x0081 RSA modulus + * tag: 0x0082 RSA exponent + * + * TAG + * [0x7f 0x49][LEN][DATA] + * _______/ \_________________ + * / \ + * [0x81][128][DATA][0x82][3][DATA] + * __/ \__ 0x01, 0x00, 0x01 + * / \ + * 0x81 0x80 + */ + + if (icc_read_buf[6] == 0x00 && icc_read_buf[5] == 0xb6) + { /* Key for Sign */ + static const char const get_data_sigkey_result[] = + { + 0x7f, 0x49, 0x81, 0x88, + 0x81, 0x81, 0x80, + /* 128-byte data */ + /* modulus */ + 0xdb, 0xca, 0x58, 0x74, 0x44, 0x8e, 0x1a, 0x2c, + 0xa0, 0x91, 0xac, 0xc4, 0xe2, 0x77, 0x2b, 0x90, + 0xcf, 0x3c, 0x7e, 0x81, 0xdc, 0x8d, 0xb0, 0xe2, + 0xf1, 0xfe, 0x56, 0x7e, 0x54, 0x57, 0xf0, 0xd8, + 0xb1, 0xb1, 0xaa, 0x9d, 0x8f, 0xb0, 0x56, 0x01, + 0xaa, 0x6b, 0xa7, 0x2e, 0xce, 0x01, 0x20, 0xd2, + 0xf8, 0xf5, 0x85, 0x3a, 0xc2, 0x73, 0xf9, 0x66, + 0x30, 0x28, 0x65, 0x5e, 0x3f, 0x91, 0xaf, 0x3f, + 0xf6, 0x1c, 0x31, 0x2f, 0xa2, 0x91, 0xbb, 0x41, + 0x91, 0x41, 0x08, 0x0a, 0xc5, 0x3e, 0x39, 0xda, + 0x2f, 0x6f, 0x58, 0x51, 0xe2, 0xd2, 0xe9, 0x42, + 0x8a, 0x7b, 0x72, 0x7b, 0x15, 0xf6, 0xf6, 0x6a, + 0x12, 0x6e, 0x0c, 0x15, 0x24, 0x13, 0x16, 0x55, + 0x3a, 0xf1, 0xa7, 0x16, 0x3e, 0xe9, 0xc8, 0x3d, + 0x2c, 0x3d, 0xae, 0x51, 0x2d, 0x7f, 0xef, 0x92, + 0x25, 0x6a, 0xbb, 0x02, 0x03, 0x70, 0x45, 0x3d, + /* public exponent */ + 0x82, 3, 0x01, 0x00, 0x01 + }; + + icc_result_value = get_data_sigkey_result; + icc_result_len = sizeof (get_data_sigkey_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + } +#if 0 + else if (icc_read_buf[6] == 0x00 && icc_read_buf[5] == 0xb8) + { /* Key for Encryption */ + static const char const get_data_enckey_result[] = + { + 0x7f, 0x49, 0x81, 0x88, + 0x81, 0x81, 0x80, + /* 128-byte data */ + 0xB2, 0x19, 0x91, 0x42, 0x27, 0xC7, 0x97, 0xFE, + 0x92, 0x64, 0x42, 0xCA, 0xE3, 0x66, 0x4D, 0xD0, + 0x31, 0xE4, 0x10, 0x31, 0x0F, 0xC7, 0x07, 0x4A, + 0xAA, 0x6D, 0x31, 0xA2, 0x88, 0x68, 0xAF, 0x45, + 0x8E, 0x42, 0x12, 0xFF, 0xB6, 0xEF, 0x6E, 0x54, + 0x7E, 0x51, 0x8E, 0xBC, 0xE8, 0x18, 0x79, 0xA7, + 0xBC, 0xA8, 0x14, 0x8B, 0xE7, 0x91, 0x57, 0x38, + 0xCE, 0x4F, 0x6E, 0x16, 0x48, 0xCB, 0xD6, 0x0B, + 0x3A, 0x53, 0x70, 0xF3, 0xFC, 0xFA, 0xC3, 0x58, + 0x3D, 0xE7, 0x2A, 0x5E, 0xDD, 0xE1, 0x38, 0x82, + 0x57, 0x87, 0x3A, 0xDC, 0x34, 0xDE, 0xCD, 0x5D, + 0x33, 0x1C, 0xAB, 0xB0, 0x1B, 0xEE, 0x82, 0x43, + 0x7B, 0xAC, 0xF8, 0xF0, 0xB2, 0x62, 0xB2, 0x6D, + 0x09, 0xED, 0x2E, 0xD1, 0xBA, 0xB8, 0xC6, 0x96, + 0xFA, 0x3E, 0xB4, 0xE3, 0xFE, 0x68, 0xF9, 0x51, + 0x9A, 0x8C, 0x8B, 0x20, 0x93, 0xD0, 0x2E, 0x0F, + 0x82, 3, 0x01, 0x00, 0x01 + }; + + icc_result_value = get_data_enckey_result; + icc_result_len = sizeof (get_data_enckey_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + } +#endif + /* icc_read_buf[5] == 0xa4 */ + else + { + icc_result_value = 0x6a88; /* No record */ + icc_result_len = 0; + icc_result_flag = 0; + } + } + else + { + icc_result_value = 0x6a88; /* No record */ + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[1] == INS_READ_BINARY) + { /* it must be for DF 0x2f02 */ + stx_put_string (" - Read binary\r\n"); + + if (icc_read_buf[3] >= 6) + { + icc_result_value = 0x6b00; /* BAD_P0_P1 */ + icc_result_len = 0; + icc_result_flag = 0; + } + else + { /* Tag 5a, serial number */ + static const char const get_data_rb_result[] = { 0x5a, 0x4, 0x01, 0x02, 0x03, 0x04 }; + + icc_result_value = (word)get_data_rb_result; + icc_result_len = sizeof (get_data_rb_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + + /* XXX: Next get response returns 6282??? eof_reached ??? */ + } + } + else if (icc_read_buf[1] == INS_SELECT_FILE) + { + if (icc_read_buf[2] == 4) /* Selection by DF name */ + { + stx_put_string (" - select DF by name\r\n"); + /* + * XXX: Should return contents. + */ + + if (1) + { + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[4] == 2 + && icc_read_buf[5] == 0x2f + && icc_read_buf[6] == 02) + { + stx_put_string (" - select 0x2f02 EF\r\n"); + /* + * MF.EF-GDO -- Serial number of the card and name of the owner + */ + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + else + if (icc_read_buf[4] == 2 + && icc_read_buf[5] == 0x3f + && icc_read_buf[6] == 0) + { + stx_put_string (" - select ROOT MF\r\n"); + if (icc_read_buf[3] == 0x0c) + { + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + else + { + icc_result_value = select_file_TOP_result; + icc_result_len = sizeof (select_file_TOP_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + } + } + else + { + stx_put_string (" - select ?? \r\n"); + + icc_result_value = 0x6a82; /* File missing */ + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[1] == INS_GET_DATA) + { + stx_put_string (" - Get Data\r\n"); + + switch (((icc_read_buf[2]<<8) | icc_read_buf[3])) + { + case 0x4f: /* AID */ + { + icc_result_value = (word)&do_4f[2]; + icc_result_len = sizeof (do_4f) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5e: /* Login data */ + { + icc_result_value = (word)get_data_5e_result; + icc_result_len = sizeof (get_data_5e_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x64: + { + icc_result_value = (word)get_data_64_result; + icc_result_len = sizeof (get_data_64_result); + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc0: + { + icc_result_value = (word)&do_c0[2]; + icc_result_len = sizeof (do_c0) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc4: + { + icc_result_value = (word)&do_c4[2]; + icc_result_len = sizeof (do_c4) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5b: /* Name */ + { + icc_result_value = (word)&do_5b[2]; + icc_result_len = sizeof (do_5b) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x93: /* Digital Signature Counter (3-bytes) */ + { + icc_result_value = (word)&do_93[2]; + icc_result_len = sizeof (do_93) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc5: /* Fingerprints */ + { + icc_result_value = &do_c5[2]; + icc_result_len = sizeof (do_c5) - 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5f2d: /* Language preference */ + { + icc_result_value = (word)&do_5f2d[3]; + icc_result_len = sizeof (do_5f2d) - 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5f35: /* Sex */ + { + icc_result_value = (word)&do_5f35[3]; + icc_result_len = sizeof (do_5f35) - 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x5f50: /* URL */ + { + icc_result_value = (word)&do_5f50[3]; + icc_result_len = sizeof (do_5f50) - 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x65: /* Card Holder Related Data (Tag) */ + { + icc_result_value = (word)do_65_head; + icc_result_len = do_65_head[1] + 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x6e: /* Application Related Data (Tag) */ + { + icc_result_value = (word)do_6e_head; + icc_result_len = do_6e_head[2] + 3; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0x7a: /* Security Support Template (Tag) */ + { + icc_result_value = (word)do_7a_head; + icc_result_len = do_7a_head[1] + 2; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_ROM; + break; + } + case 0xc6: /* List of CA fingerprints */ + case 0xcd: /* List of generation dates/times public-key pairs */ + default: + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + } + else if (icc_read_buf[1] == INS_PSO) + { + stx_put_string (" - PSO\r\n"); + + if (icc_read_buf[2] == 0x9E && icc_read_buf[3] == 0x9A) + { + if (icc_read_len != 5 + 35 && icc_read_len != 5 + 35 + 1) + stx_put_string (" wrong length\r\n"); + else + { + icc_result_value = rsa_sign (&icc_read_buf[5]); + icc_result_len = RSA_SIGNATURE_LENGTH; + icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_RAM; + } + + stx_put_string ("done.\r\n"); + } + else + { + stx_put_string (" - ???\r\n"); + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + } + else + { + stx_put_string (" - ???\r\n"); + icc_result_value = 0x9000; + icc_result_len = 0; + icc_result_flag = 0; + } + + return 0; +} + +#define ICC_RESULT_MAX_LEN 32 + +static byte +send_result_adpu (void) +{ + byte r = 0; + + if ((icc_result_flag & ICC_RESULT_BUF)) + { + if ((icc_result_flag & ICC_RESULT_BUF_MASK) == ICC_RESULT_BUF_ROM + || (icc_result_flag & ICC_RESULT_BUF_MASK) == ICC_RESULT_BUF_RAM) + { + byte r; + + asm volatile ("cli"); + icc_status = ICC_STATUS_DATA; + icc_write_task = current; + task_wait_bits |= taskset_current (); + r = stx_yield (); + + if (r == 0) + { + if (icc_result_len <= ICC_RESULT_MAX_LEN) + { + icc_write_buf[0] = 0x90; + icc_write_buf[1] = 0x00; + } + else + { + icc_result_len -= ICC_RESULT_MAX_LEN; + icc_result_value += ICC_RESULT_MAX_LEN; + icc_write_buf[0] = 0x61; + icc_write_buf[1] = icc_result_len; + } + + icc_write_len = 2; + asm volatile ("cli"); + icc_status = ICC_STATUS_SW; + icc_write_task = current; + task_wait_bits |= taskset_current (); + stx_yield (); + } + } + else + ; + } + else /* Status word */ + { + icc_write_buf[0] = (icc_result_value >> 8); + icc_write_buf[1] = (icc_result_value & 0xff); + icc_write_len = 2; + + asm volatile ("cli"); + icc_status = ICC_STATUS_SW; + icc_write_task = current; + task_wait_bits |= taskset_current (); + stx_yield (); + } + + return r; +} + +byte +stx_icc_wait_power_on (void) +{ + stx_put_string ("W\r\n"); + asm volatile ("cli"); + icc_status = ICC_STATUS_DATA; /* Ready to send ATR */ + icc_wait_task = current; + task_wait_bits |= taskset_current (); + stx_yield (); + + stx_put_string ("w\r\n"); + if (icc_wait_result) + { + char s[10]; + sprintf(s,"On %d\r\n", icc_wait_task); + stx_put_string (s); + } + else + stx_put_string ("Off?\r\n"); + return icc_wait_result; +} + +void +icc_main (void) +{ +#if 1 + word old_sp = icc_initial_sp; + + icc_status = ICC_STATUS_BUSY; + icc_wait_task = 0; + icc_write_task = 0; + icc_read_task = 0; + + icc_initial_sp = task[ICC_TASK] + 32 + 1 + 2; + + if (old_sp != icc_initial_sp) + stx_put_string ("Start\r\n"); + else + stx_put_string ("RESET\r\n"); +#else + char s[12]; + sprintf(s, "Start %d\r\n", current); + stx_put_string (s); +#endif + + again: + if (stx_icc_wait_power_on ()) + while (1) + { + byte r; + r = receive_command_adpu (); + + if (r == 0xff) /* wait for XFR_BLOCK */ + break; + + if (r == 0) + { + stx_put_string ("zero size command packet\r\n"); + continue; + } + + if (process_command_adpu ()) + continue; + + if (send_result_adpu () == 0xff) + break; + } + + stx_put_string ("Reset\r\n"); + goto again; +} diff --git a/src/usb.c b/src/usb.c new file mode 100644 index 0000000..51f08dd --- /dev/null +++ b/src/usb.c @@ -0,0 +1,148 @@ +/* + * usb.c -- + * + * Copyright (C) 2010 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Gnuk, a GnuPG USB Token implementation. + * + * Gnuk 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 3 of the License, or + * (at your option) any later version. + * + * Gnuk 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, see . + * + */ + +#define ICC_POWER_ON 0x62 +0 bMessageType 0x62 +1 dwLength 0x00000000 +5 bSlot 0x00 FIXED +6 bSeq 0x00-FF +7 bReserved 0x01 FIXED +8 abRFU 0x0000 + +0 bMessageType 0x80 Indicates RDR_to_PC_DataBlock +1 dwLength Size of bytes for the ATR +5 bSlot 0x00 FIXED +6 bSeq Sequence number for the corresponding command. +7 bStatus USB-ICC Status register as defined in Table 6.1-8 +8 bError USB-ICC Error register as defined in Table 6.1-9 +9 bChainParameter 0x00 Indicates that this message contains the complete ATR. +10 abData ATR + + + +#define ICC_POWER_OFF 0x63 + 0 bMessageType 0x63 Indicates PC_to_RDR_IccPowerOn + 1 dwLength 0x00000000 Message-specific data length + 5 bSlot 0x00 FIXED + 6 bSeq 0x00-FF Sequence number for command. + 7 abRFU 0x000000 + + 0 bMessageType 81h Indicates RDR_to_PC_SlotStatus + 1 dwLength 0x00000000 Message-specific data length + 5 bSlot 0x00 FIXED + 6 bSeq Sequence number for the corresponding command. + 7 bStatus USB-ICC Status register as defined in Table 6.1-8 + 8 bError USB-ICC Error register as defined in Table 6.1-9 + 9 bReserved 0x00 FIXED + + +#define XFR_BLOCK 0x6F +0 bMessageType 0x6F Indicates PC_to_RDR_XfrBlock +1 dwLength Size of abData field of this message +5 bSlot 0x00 FIXED +6 bSeq 0x00-FF Sequence number for command. +7 bReserved 0x00 FIXED +8 wLevelParameter + 0x0000 + the command APDU begins and ends with this command + + 0x0001 + the command APDU begins with this command, and + continue in the next PC_to_RDR_XfrBlock + + 0x0002 + this abData field continues a command APDU and + ends the command APDU + + 0x0003 + the abData field continues a command APDU and + another block is to follow + + 0x0010 + empty abData field, continuation of response APDU + is expected in the next RDR_to_PC_DataBlock. + +10 abData Data block sent to the USB-ICC + + +0 bMessageType 0x80 Indicates RDR_to_PC_DataBlock +1 dwLength Size of abData field of this message +5 bSlot 0x00 FIXED +6 bSeq Sequence number for the corresponding command. + +7 bStatus USB-ICC Status register as defined in Table 6.1-8 +8 bError USB-ICC Error register as defined in Table 6.1-9 +9 bChainParameter + Indicates if the response is complete, to be + continued or if the command APDU can continue + 0x00: The response APDU begins and ends in this command + 0x01: The response APDU begins with this command and is to continue + 0x02: This abData field continues the response + APDU and ends the response APDU + 0x03: This abData field continues the response + APDU and another block is to follow + 0x10: Empty abData field, continuation of the + command APDU is expected in next PC_to_RDR_XfrBlock command +10 abData + + +/* status code and error code */ +0 bmIccStatus 1 0, 1, 2 0= The USB-ICC is present and activated. + (2 bits) 1= The USB-ICC is present but not activated +(2 bits) 2= The USB-ICC is virtually not present + 3= RFU + (4 bits) RFU +(6 bits) bmCommandStatus (2 bits) 0, 1, 2 0= Processed without error. + 1= Failed, error condition given by bError. + 2= Time extension is requested + 3= RFU +1 bError 1 Error codes + + +/* error code */ +ICC_MUTE 0xFE The applications of the USB-ICC did not respond + or the ATR could not be sent by the USB-ICC. +XFR_OVERRUN 0xFC The USB-ICC detected a buffer overflow when + receiving a data block. +HW_ERROR 0xFB The USB-ICC detected a hardware error. + + (0xC0 to 0x81) User defined + + 0xE0, 0xEF, 0xF0, These values shall not be used by the USB-ICC + 0xF2..0xF8, 0xFD + + all others Reserved for future use + (0x80 and those filling the gaps) + +extern const uchar *icc_power_on (void); +extern byte icc_get_status (void); + + +PC_to_RDR_IccPowerOff +RDR_to_PC_SlotStatus + +PC_to_RDR_IccPowerOn +RDR_to_PC_DataBlock + +PC_to_RDR_XfrBlock +RDR_to_PC_DataBlock diff --git a/src/usb_conf.h b/src/usb_conf.h new file mode 100644 index 0000000..37c2777 --- /dev/null +++ b/src/usb_conf.h @@ -0,0 +1,81 @@ +/* +(C) COPYRIGHT 2010 STMicroelectronics +usb_conf.h +MCD Application Team +V3.1.1 +04/07/2010 +Virtual COM Port Demo configuration header +*/ + +#ifndef __USB_CONF_H +#define __USB_CONF_H + +/*-------------------------------------------------------------*/ +/* EP_NUM */ +/* defines how many endpoints are used by the device */ +/*-------------------------------------------------------------*/ + +#define EP_NUM (6) + +/*-------------------------------------------------------------*/ +/* -------------- Buffer Description Table -----------------*/ +/*-------------------------------------------------------------*/ +/* buffer table base address */ +/* buffer table base address */ +#define BTABLE_ADDRESS (0x00) + +/* EP0 */ +/* rx/tx buffer base address */ +#define ENDP0_RXADDR (0x40) +#define ENDP0_TXADDR (0x80) + +/* EP1 */ +/* tx buffer base address */ +#define ENDP1_TXADDR (0xC0) +/* EP2 */ +#define ENDP2_TXADDR (0x100) +/* EP3 */ +#define ENDP3_RXADDR (0x110) + + +/* EP4 */ +#define ENDP4_TXADDR (0x180) +/* EP5 */ +#define ENDP5_RXADDR (0x1C0) + +/*-------------------------------------------------------------*/ +/* ------------------- ISTR events -------------------------*/ +/*-------------------------------------------------------------*/ +/* IMR_MSK */ +/* mask defining which events has to be handled */ +/* by the device application software */ +#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM ) + +/*#define CTR_CALLBACK*/ +/*#define DOVR_CALLBACK*/ +/*#define ERR_CALLBACK*/ +/*#define WKUP_CALLBACK*/ +/*#define SUSP_CALLBACK*/ +/*#define RESET_CALLBACK*/ +/*#define SOF_CALLBACK*/ +/*#define ESOF_CALLBACK*/ + +#if 0 +#define EP1_IN_Callback NOP_Process +#define EP2_IN_Callback NOP_Process +#define EP3_IN_Callback NOP_Process +#define EP4_IN_Callback NOP_Process +#define EP5_IN_Callback NOP_Process +#define EP6_IN_Callback NOP_Process +#define EP7_IN_Callback NOP_Process + +#define EP1_OUT_Callback NOP_Process +#define EP2_OUT_Callback NOP_Process +#define EP3_OUT_Callback NOP_Process +#define EP4_OUT_Callback NOP_Process +#define EP5_OUT_Callback NOP_Process +#define EP6_OUT_Callback NOP_Process +#define EP7_OUT_Callback NOP_Process +#endif + +#endif /* __USB_CONF_H */ diff --git a/src/usb_desc.c b/src/usb_desc.c new file mode 100644 index 0000000..4b830f4 --- /dev/null +++ b/src/usb_desc.c @@ -0,0 +1,206 @@ +/* + * + */ + +#include "usb_lib.h" +#include "usb_desc.h" + +#define USB_ICC_INTERFACE_CLASS 0x0B +#define USB_ICC_INTERFACE_SUBCLASS 0x00 +#define USB_ICC_INTERFACE_BULK_PROTOCOL 0x00 +#define USB_ICC_DATA_SIZE 64 + +/* USB Standard Device Descriptor */ +static const uint8_t gnukDeviceDescriptor[] = { + 18, /* bLength */ + USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x00, 0x02, /* bcdUSB = 2.00 */ + 0x00, /* bDeviceClass: 0 means deferred to interface */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0xff, 0xff, /* idVendor = 0xffff */ + 0x01, 0x00, /* idProduct = 0x0001 */ + 0x00, 0x02, /* bcdDevice = 2.00 */ + 1, /* Index of string descriptor describing manufacturer */ + 2, /* Index of string descriptor describing product */ + 3, /* Index of string descriptor describing the device's serial number */ + 0x01 /* bNumConfigurations */ +}; + +/* Configuation Descriptor */ +static const uint8_t gnukConfigDescriptor[] = { + 9, /* bLength: Configuation Descriptor size */ + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ + 9+9+54+7+7+9+5+5+4+5+7+9+7+7, 0x00, /* wTotalLength:no of returned bytes */ + 0x03, /* bNumInterfaces: 3 interfaces (two for CDC, one for GPG) */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ + 0xC0, /* bmAttributes: self powered */ + 0x32, /* MaxPower 0 mA */ + + /* Interface Descriptor */ + 9, /* bLength: Interface Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ + 0, /* Index of this interface */ + 0, /* Alternate setting for this interface */ + 2, /* bNumEndpoints: Bulk-IN, Bulk-OUT */ + USB_ICC_INTERFACE_CLASS, + USB_ICC_INTERFACE_SUBCLASS, + USB_ICC_INTERFACE_BULK_PROTOCOL, + 0, /* string index for interface */ + + /* ICC Descriptor */ + 54, /* bLength: */ + 0x21, /* bDescriptorType: USBDESCR_ICC */ + 0x10, 0x01, /* bcdCCID: 1.1 */ + 0, /* bMaxSlotIndex: */ + 1, /* bVoltageSupport: FIXED VALUE */ + 0x02, 0, 0, 0, /* dwProtocols: T=1 */ + 0xfc, 0x0d, 0, 0, /* dwDefaultClock: FIXED VALUE */ + 0xfc, 0x0d, 0, 0, /* dwMaximumClock: FIXED VALUE*/ + 1, /* bNumClockSupported: FIXED VALUE*/ + 0x80, 0x25, 0, 0, /* dwDataRate: FIXED VALUE */ + 0x80, 0x25, 0, 0, /* dwMaxDataRate: FIXED VALUE */ + 1, /* bNumDataRateSupported: FIXED VALUE */ + 0xfe, 0, 0, 0, /* dwMaxIFSD: */ + 0, 0, 0, 0, /* dwSynchProtocols: FIXED VALUE */ + 0, 0, 0, 0, /* dwMechanical: FIXED VALUE */ + 0x40, 0x08, 0x04, 0x00, /* dwFeatures: Short and extended ADPU level */ + 0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 261+10 */ + 0xff, /* bClassGetResponse: */ + 0xff, /* bClassEnvelope: */ + 0, 0, /* wLCDLayout: FIXED VALUE */ + 0, /* bPinSupport: No PIN pad */ + 1, /* bMaxCCIDBusySlots: 1 */ + /*Endpoint 4 Descriptor*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x84, /* bEndpointAddress: (IN4) */ + 0x02, /* bmAttributes: Bulk */ + USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */ + 0x00, /* bInterval */ + /*Endpoint 5 Descriptor*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x05, /* bEndpointAddress: (OUT5) */ + 0x02, /* bmAttributes: Bulk */ + USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */ + 0x00, /* bInterval */ + + /* Interface Descriptor */ + 9, /* bLength: Interface Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ + 0x01, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x01, /* bInterfaceProtocol: Common AT commands */ + 0x00, /* iInterface: */ + /*Header Functional Descriptor*/ + 5, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Managment Functional Descriptor*/ + 5, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ + 0x01, /* bDataInterface: 1 */ + /*ACM Functional Descriptor*/ + 4, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 5, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ + 0x00, /* bMasterInterface: Communication class interface */ + 0x01, /* bSlaveInterface0: Data Class Interface */ + /*Endpoint 2 Descriptor*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x82, /* bEndpointAddress: (IN2) */ + 0x03, /* bmAttributes: Interrupt */ + VIRTUAL_COM_PORT_INT_SIZE, 0x00, /* wMaxPacketSize: */ + 0xFF, /* bInterval: */ + + /*Data class interface descriptor*/ + 9, /* bLength: Endpoint Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ + 0x02, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x00, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint 3 Descriptor*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x03, /* bEndpointAddress: (OUT3) */ + 0x02, /* bmAttributes: Bulk */ + VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */ + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint 1 Descriptor*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x81, /* bEndpointAddress: (IN1) */ + 0x02, /* bmAttributes: Bulk */ + VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */ + 0x00 /* bInterval */ +}; + + +/* USB String Descriptors */ +static const uint8_t gnukStringLangID[] = { + 4, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, + 0x09, 0x04 /* LangID = 0x0409: US-English */ +}; + +static const uint8_t gnukStringVendor[] = { + 33*2+2, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType*/ + /* Manufacturer: "Free Software Initiative of Japan" */ + 'F', 0, 'r', 0, 'e', 0, 'e', 0, ' ', 0, 'S', 0, 'o', 0, 'f', 0, + 't', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'I', 0, 'n', 0, + 'i', 0, 't', 0, 'i', 0, 'a', 0, 't', 0, 'i', 0, 'v', 0, 'e', 0, + ' ', 0, 'o', 0, 'f', 0, ' ', 0, 'J', 0, 'a', 0, 'p', 0, 'a', 0, + 'n', 0 +}; + +static const uint8_t gnukStringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT] = { + 14*2+2, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + /* Product name: "FSIJ USB Token" */ + 'F', 0, 'S', 0, 'I', 0, 'J', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, + ' ', 0, 'T', 0, 'o', 0, 'k', 0, 'e', 0, 'n', 0 +}; + +static uint8_t gnukStringSerial[] = { + 8, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + '2', 0, '.', 0, '0', 0 +}; + +ONE_DESCRIPTOR Device_Descriptor = { + (uint8_t*)gnukDeviceDescriptor, + sizeof (gnukDeviceDescriptor) +}; + +ONE_DESCRIPTOR Config_Descriptor = { + (uint8_t*)gnukConfigDescriptor, + sizeof (gnukConfigDescriptor) +}; + +ONE_DESCRIPTOR String_Descriptor[4] = { + {(uint8_t*)gnukStringLangID, sizeof (gnukStringLangID)}, + {(uint8_t*)gnukStringVendor, sizeof (gnukStringVendor)}, + {(uint8_t*)gnukStringProduct, sizeof (gnukStringProduct)}, + {(uint8_t*)gnukStringSerial, sizeof (gnukStringSerial)}, +}; diff --git a/src/usb_lld.c b/src/usb_lld.c new file mode 100644 index 0000000..46ec98c --- /dev/null +++ b/src/usb_lld.c @@ -0,0 +1,26 @@ +#include "ch.h" +#include "hal.h" +#include "usb_lld.h" + +extern void USB_Istr (void); + +CH_IRQ_HANDLER (Vector90) { + CH_IRQ_PROLOGUE(); + + USB_Istr(); + + CH_IRQ_EPILOGUE(); +} + +void usb_lld_init (void) { + RCC->APB1ENR |= RCC_APB1ENR_USBEN; + NVICEnableVector (USB_LP_CAN1_RX0_IRQn, + CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY)); + /* + * Note that we also have other IRQs: + * USB_HP_CAN1_TX_IRQn + * USBWakeUp_IRQn + */ + RCC->APB1RSTR = RCC_APB1RSTR_USBRST; + RCC->APB1RSTR = 0; +} diff --git a/src/usb_lld.h b/src/usb_lld.h new file mode 100644 index 0000000..3547ff5 --- /dev/null +++ b/src/usb_lld.h @@ -0,0 +1,8 @@ +/** + * @brief USB interrupt priority level setting. + */ +#if !defined(STM32_USB_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_USB_IRQ_PRIORITY 11 +#endif + +void usb_lld_init (void); diff --git a/src/usb_prop.c b/src/usb_prop.c new file mode 100644 index 0000000..73e8d4e --- /dev/null +++ b/src/usb_prop.c @@ -0,0 +1,299 @@ +/* +usb_prop.c +MCD Application Team +V3.1.1 +04/07/2010 +All processing related to Virtual Com Port Demo +*/ + +#include "usb_lib.h" +#include "usb_conf.h" +#include "usb_prop.h" +#include "usb_desc.h" +#include "usb_pwr.h" +#include "hw_config.h" + +#if 0 +static uint8_t Request = 0; +#endif + +typedef struct +{ + uint32_t bitrate; + uint8_t format; + uint8_t paritytype; + uint8_t datatype; +} LINE_CODING; + +static LINE_CODING linecoding = { + 115200, /* baud rate*/ + 0x00, /* stop bits-1*/ + 0x00, /* parity - none*/ + 0x08 /* no. of bits 8*/ +}; + +static uint8_t *Virtual_Com_Port_GetLineCoding(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding); + return NULL; + } + + return (uint8_t *)&linecoding; +} + +static uint8_t *Virtual_Com_Port_SetLineCoding(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding); + return NULL; + } + + return (uint8_t *)&linecoding; +} + + +#define GNUK_MAX_PACKET_SIZE 64 + +static void +gnuk_device_init (void) +{ + + /* Update the serial number string descriptor with the data from the unique + ID*/ + Get_SerialNum (); + + pInformation->Current_Configuration = 0; + + /* Connect the device */ + PowerOn (); + + /* Perform basic device initialization operations */ + USB_SIL_Init (); + + bDeviceState = UNCONNECTED; +} + +static void +gnuk_device_reset (void) +{ + /* Set Virtual_Com_Port DEVICE as not configured */ + pInformation->Current_Configuration = 0; + + /* Current Feature initialization */ + pInformation->Current_Feature = Config_Descriptor.Descriptor[7]; + + /* Set Virtual_Com_Port DEVICE with the default Interface*/ + pInformation->Current_Interface = 0; + + SetBTABLE (BTABLE_ADDRESS); + + /* Initialize Endpoint 0 */ + SetEPType (ENDP0, EP_CONTROL); + SetEPTxStatus (ENDP0, EP_TX_STALL); + SetEPRxAddr (ENDP0, ENDP0_RXADDR); + SetEPTxAddr (ENDP0, ENDP0_TXADDR); + Clear_Status_Out (ENDP0); + SetEPRxCount (ENDP0, GNUK_MAX_PACKET_SIZE); + SetEPRxValid (ENDP0); + + /* Initialize Endpoint 1 */ + SetEPType (ENDP1, EP_BULK); + SetEPTxAddr (ENDP1, ENDP1_TXADDR); + SetEPTxStatus (ENDP1, EP_TX_NAK); + SetEPRxStatus (ENDP1, EP_RX_DIS); + + /* Initialize Endpoint 2 */ + SetEPType (ENDP2, EP_INTERRUPT); + SetEPTxAddr (ENDP2, ENDP2_TXADDR); + SetEPRxStatus (ENDP2, EP_RX_DIS); + SetEPTxStatus (ENDP2, EP_TX_NAK); + + /* Initialize Endpoint 3 */ + SetEPType (ENDP3, EP_BULK); + SetEPRxAddr (ENDP3, ENDP3_RXADDR); + SetEPRxCount (ENDP3, VIRTUAL_COM_PORT_DATA_SIZE); + SetEPRxStatus (ENDP3, EP_RX_VALID); + SetEPTxStatus (ENDP3, EP_TX_DIS); + + /* Initialize Endpoint 4 */ + SetEPType (ENDP4, EP_BULK); + SetEPTxAddr (ENDP4, ENDP4_TXADDR); + SetEPTxStatus (ENDP4, EP_TX_NAK); + SetEPRxStatus (ENDP4, EP_RX_DIS); + + /* Initialize Endpoint 5 */ + SetEPType (ENDP5, EP_BULK); + SetEPRxAddr (ENDP5, ENDP5_RXADDR); + SetEPRxCount (ENDP5, VIRTUAL_COM_PORT_DATA_SIZE); /* XXX */ + SetEPRxStatus (ENDP5, EP_RX_VALID); + SetEPTxStatus (ENDP5, EP_TX_DIS); + + /* Set this device to response on default address */ + SetDeviceAddress (0); + + bDeviceState = ATTACHED; +} + +static void +gnuk_device_SetConfiguration (void) +{ + DEVICE_INFO *pInfo = &Device_Info; + + if (pInfo->Current_Configuration != 0) + /* Device configured */ + bDeviceState = CONFIGURED; +} + +static void +gnuk_device_SetDeviceAddress (void) +{ + bDeviceState = ADDRESSED; +} + +/* IN from port 0 */ +static void +gnuk_device_Status_In (void) +{ +#if 0 + if (Request == SET_LINE_CODING) + Request = 0; +#endif +} + +/* OUT to port 0 */ +static void +gnuk_device_Status_Out (void) +{ +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_Data_Setup +* Description : handle the data class specific requests +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +static RESULT +Virtual_Com_Port_Data_Setup (uint8_t RequestNo) +{ + uint8_t *(*CopyRoutine)(uint16_t); + + CopyRoutine = NULL; + + if (RequestNo == GET_LINE_CODING) + { + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + CopyRoutine = Virtual_Com_Port_GetLineCoding; + } + else if (RequestNo == SET_LINE_CODING) + { + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + CopyRoutine = Virtual_Com_Port_SetLineCoding; +#if 0 + Request = SET_LINE_CODING; +#endif + } + + if (CopyRoutine == NULL) + return USB_UNSUPPORT; + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine) (0); + + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_NoData_Setup. +* Description : handle the no data class specific requests. +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +static RESULT +Virtual_Com_Port_NoData_Setup (uint8_t RequestNo) +{ + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + { + if (RequestNo == SET_COMM_FEATURE) + return USB_SUCCESS; + else if (RequestNo == SET_CONTROL_LINE_STATE) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static uint8_t * +gnuk_device_GetDeviceDescriptor (uint16_t Length) +{ + return Standard_GetDescriptorData (Length, &Device_Descriptor); +} + +static uint8_t * +gnuk_device_GetConfigDescriptor (uint16_t Length) +{ + return Standard_GetDescriptorData (Length, &Config_Descriptor); +} + +static uint8_t * +gnuk_device_GetStringDescriptor (uint16_t Length) +{ + uint8_t wValue0 = pInformation->USBwValue0; + + if (wValue0 > (sizeof (String_Descriptor) / sizeof (ONE_DESCRIPTOR))) + return NULL; + else + return Standard_GetDescriptorData (Length, &String_Descriptor[wValue0]); +} + +static RESULT +gnuk_device_Get_Interface_Setting (uint8_t Interface, uint8_t AlternateSetting) +{ + if (AlternateSetting > 0) + return USB_UNSUPPORT; + else if (Interface > 1) + return USB_UNSUPPORT; + + return USB_SUCCESS; +} + +/* + * Interface to USB core + */ + +DEVICE_PROP Device_Property = { + gnuk_device_init, + gnuk_device_reset, + gnuk_device_Status_In, + gnuk_device_Status_Out, + Virtual_Com_Port_Data_Setup, + Virtual_Com_Port_NoData_Setup, + gnuk_device_Get_Interface_Setting, + gnuk_device_GetDeviceDescriptor, + gnuk_device_GetConfigDescriptor, + gnuk_device_GetStringDescriptor, + 0, + GNUK_MAX_PACKET_SIZE +}; + +DEVICE Device_Table = { + EP_NUM, + 1 +}; + +USER_STANDARD_REQUESTS User_Standard_Requests = { + NOP_Process, /* GetConfiguration */ + gnuk_device_SetConfiguration, + NOP_Process, /* GetInterface */ + NOP_Process, /* SetInterface */ + NOP_Process, /* GetStatus */ + NOP_Process, /* ClearFeature */ + NOP_Process, /* SetEndPointFeature */ + NOP_Process, /* SetDeviceFeature */ + gnuk_device_SetDeviceAddress +}; diff --git a/src/usb_prop.h b/src/usb_prop.h new file mode 100644 index 0000000..ab42890 --- /dev/null +++ b/src/usb_prop.h @@ -0,0 +1,26 @@ +/* +(C) COPYRIGHT 2010 STMicroelectronics +usb_prop.h +MCD Application Team +V3.1.1 +04/07/2010 +All processing related to Virtual COM Port Demo (Endpoint 0) +*/ + +#ifndef __usb_prop_H +#define __usb_prop_H + +#define SEND_ENCAPSULATED_COMMAND 0x00 +#define GET_ENCAPSULATED_RESPONSE 0x01 +#define SET_COMM_FEATURE 0x02 +#define GET_COMM_FEATURE 0x03 +#define CLEAR_COMM_FEATURE 0x04 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +extern ONE_DESCRIPTOR Device_Descriptor; +extern ONE_DESCRIPTOR Config_Descriptor; +extern ONE_DESCRIPTOR String_Descriptor[4]; +#endif /* __usb_prop_H */ diff --git a/src/usbcdc.mk b/src/usbcdc.mk index a8dcf00..3f163a5 100644 --- a/src/usbcdc.mk +++ b/src/usbcdc.mk @@ -1,4 +1,3 @@ USBCDCDIR = ../USBCDC -USBCDCSRC= $(USBCDCDIR)/usb_desc.c \ - $(USBCDCDIR)/usb_endp.c $(USBCDCDIR)/usb_istr.c \ - $(USBCDCDIR)/usb_prop.c $(USBCDCDIR)/usb_pwr.c +USBCDCSRC= $(USBCDCDIR)/usb_endp.c $(USBCDCDIR)/usb_istr.c \ + $(USBCDCDIR)/usb_pwr.c