diff --git a/.gitignore b/.gitignore index 4029f69..8233be1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,17 @@ -# generated files by 'configure' -src/Makefile -src/config.h -src/gnuk.ld *.lst *.o *.pyc src/.dep +src/Makefile +src/config.h +src/gnuk.ld src/gnuk.bin src/gnuk.dmp src/gnuk.elf src/gnuk.hex src/gnuk.map -src/random_bits +src/*.inc +regnual/regnual.bin +regnual/regnual.hex +regnual/regnual.elf +doc/_build diff --git a/AUTHORS b/AUTHORS index f9cb335..ec2f636 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,14 @@ Kaz Kojima: NIIBE Yutaka: Founder of the project. + Added FST_01 support: + boards/FST_01/board.c + boards/FST_01/board.h + boards/FST_01/mcuconf.h + Added FST_01_00 support: + boards/FST_01_00/board.c + boards/FST_01_00/board.h + boards/FST_01_00/mcuconf.h Added STBee support: boards/STBEE/board.c boards/STBEE/board.h @@ -28,26 +36,40 @@ NIIBE Yutaka: tool/intel_hex.py Wrote a tool for Gnuk: tool/gnuk_put_binary.py - Wrote: + tool/gnuk_put_binary_libusb.py + tool/gnuk_remove_keys.py + tool/gnuk_upgrade.py + Wrote a tool for USB Hub: + tool/hub_ctrl.py + Wrote a tool for testing card reader with pinpad: + tool/pinpadtest.py + Wrote reGNUal implementation: + regnual/regnual.c + regnual/sys.c + Wrote Gnuk implementation: gnuk.svg src/configure src/ac.c - src/main.c - src/usb_lld.h - src/gnuk.h - src/usb_lld.c - src/usb-icc.c - src/openpgp-do.c - src/flash.c - src/debug.c - src/usb_desc.c - src/usb-cdc-vport.c - src/hardclock.c - src/openpgp.h - src/openpgp.c src/call-rsa.c - src/random.c + src/debug.c + src/flash.c + src/gnuk.h + src/main.c + src/neug.c + src/openpgp-do.c + src/openpgp.c + src/openpgp.h src/pin-cir.c src/pin-dial.c + src/pin-dnd.c + src/random.c + src/sys.c + src/usb-icc.c + src/usb-msc.c + src/usb-msc.h + src/usb_ctrl.c + src/usb_desc.c + src/usb_lld.c + src/usb_lld.h * and others. diff --git a/ChangeLog b/ChangeLog index 2e649c1..76bc4b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1395 @@ +2013-01-30 Niibe Yutaka + + * src/openpgp.c (cmd_external_authenticate): Fix off-by-one error. + + * tool/gnuk_token.py (gnuk_token.cmd_external_authenticate): Add + KEYNO to the arguments. + + * tool/upgrade_by_passwd.py (main): Explicitly say it's KEYNO. + +2013-01-28 Niibe Yutaka + + * src/openpgp-do.c (gpg_pw_get_retry_counter): New. + * src/openpgp.c (cmd_verify): Implement VERIFY with empty data. + +2013-01-22 Niibe Yutaka + + * tool/pinpadtest.py (Card.cmd_vega_alpha_disable_empty_verify): + New. + (main): call cmd_vega_alpha_disable_empty_verify if it's + COVADIS_VEGA_ALPHA. + +2013-01-21 Niibe Yutaka + + * tool/pageant_proxy_to_gpg.py: New. + * tool/sexp.py: New. + +2013-01-20 Niibe Yutaka + + * tool/gpg_agent.py: New. + +2013-01-11 Niibe Yutaka + + * tool/pinpadtest.py: Add fixed length input. + +2012-12-25 Niibe Yutaka + + * tool/rsa.py: New. + + * tool/rsa_example.key: New. Example RSA key information. + + * tool/upgrade_by_passwd.py: New. + +2012-12-19 Niibe Yutaka + + * src/Makefile.in (USE_OPT): -O3 and -Os (was: -O2). + + * tool/gnuk_token.py (gnuk_token.stop_gnuk, gnuk_token.mem_info) + (gnuk_token.download, gnuk_token.execute) + (gnuk_token.cmd_get_challenge) + (gnuk_token.cmd_external_authenticate): New. + (gnuk_devices_by_vidpid): New. + (regnual): New. + +2012-12-18 Niibe Yutaka + + * test/gnuk.py: Remove. + + * test/features/steps.py: Use tool/gnuk_token.py. + + * tool/gnuk_put_binary_libusb.py: Use gnuk_token.py. + (main): Follow the API change. + + * tool/gnuk_token.py (list_to_string): New. + (gnuk_token.get_string, gnuk_token.increment_seq) + (gnuk_token.reset_device, gnuk_token.release_gnuk): New. + (gnuk_token.icc_power_on): Set self.atr and it's now string. + (gnuk_token.icc_send_cmd): Handle time extension. + (gnuk_token.cmd_get_response): Return string (was: list). + (gnuk_token.cmd_get_data): Return "" when success. + (gnuk_token.cmd_change_reference_data, gnuk_token.cmd_put_data) + (gnuk_token.cmd_put_data_odd) + (gnuk_token.cmd_reset_retry_counter, gnuk_token.cmd_pso) + (gnuk_token.cmd_pso_longdata) + (gnuk_token.cmd_internal_authenticate, gnuk_token.cmd_genkey) + (gnuk_token.cmd_get_public_key): New. + (compare): New. + (get_gnuk_device): New. + +2012-12-14 Niibe Yutaka + + * src/openpgp.c (cmd_change_password): Check password length + for admin less mode. + +2012-12-13 Niibe Yutaka + + * src/openpgp-do.c (gpg_do_put_data): Add GPG_SUCCESS for + completeness (it worked because of lower layer goodness). + +2012-12-12 Niibe Yutaka + + * tool/gnuk_token.py: Add module imports. + + * tool/gnuk_remove_keys.py (main): Fix data object number + for KGTIME_SIG, KGTIME_DEC and KGTIME_AUT. + + * tool/gnuk_remove_keys_libusb.py (main): Likewise. + +2012-12-05 Niibe Yutaka + + * tool/gnuk_remove_keys_libusb.py: New. + * tool/gnuk_token.py: New. + +2012-11-07 Niibe Yutaka + + * src/usb-icc.c (icc_send_data_block_internal): New. + (icc_send_data_block_time_extension): New. + (icc_handle_timeout): Use icc_send_data_block_time_extension. + (icc_send_data_block): Only one argument. + (USBthread): Follow the change. + +2012-11-01 Niibe Yutaka + + * tool/gnuk_upgrade.py (main): New option '-k' to specify keygrip + for non-smartcard key. + (gpg_sign): Support non-smartcard key. + +2012-10-31 Niibe Yutaka + + * tool/get_raw_public_key.py: New. + +2012-10-26 Niibe Yutaka + + * GNUK_USB_DEVICE_ID (Product_STRING): It's considered better not + to include vendor name. Change the name to "Gnuk Token" (was: + FSIJ USB Token). + +2012-10-13 Niibe Yutaka + + * boards/STBEE_MINI/board.c [!DFU_SUPPORT] (hwinit1): Don't run + when "user switch" is pushed. This is for JTAG/SWD debugger. + +2012-09-25 Niibe Yutaka + + * tool/stlinkv2.py (main): Print out option bytes value. + Call reset_sys before blank_check. + +2012-09-18 Niibe Yutaka + + * tool/stlinkv2.py (stlinkv2.option_bytes_erase) + (stlinkv2.flash_erase_all, stlinkv2.flash_erase_page): : Fix + OperationFailure (was OperationError). + (main): Call option_bytes_erase if it's not 0xff. + +2012-09-12 Niibe Yutaka + + * src/sha256.c: Include . + + * src/sha256.h (SHA256_DIGEST_SIZE, SHA256_BLOCK_SIZE): Move + from sha256.c. + +2012-08-29 Niibe Yutaka + + * tool/hub_ctrl.py (__main__): Fix to busnum (was: bunum). + Thanks to Henry Hu. + +2012-08-03 Niibe Yutaka + + * Version 1.0.1. + * src/usb_desc.c (gnukStringSerial): Updated. + * src/main.c (ID_OFFSET): Fix. + +2012-08-02 Niibe Yutaka + + * test/gnuk.py (gnuk_token.get_string): New. + * test/features/991_version_string.feature: New. + +2012-07-21 Niibe Yutaka + + * Version 1.0. + * src/usb_desc.c (gnukStringSerial): Updated. + + Documentation by Sphinx. + * doc/Makefile: New. + * doc/note: Old notes are moved here. + +2012-07-20 Niibe Yutaka + + * test/features/002_get_data_static.feature: Support CERTDO enabled + Gnuk for the test of extended capabilities. + * test/features/802_get_data_static.feature: Ditto. + * test/features/402_get_data_static.feature: Ditto. + +2012-07-10 Niibe Yutaka + + * test/features/*: Add test cases for PW1/PW3 of factory settings. + + * test/features/202_keygen.feature: Add PSO signature test after + keygen. + * test/features/602_keygen.feature: Ditto. + + Bug fix. + * src/openpgp-do.c (gpg_do_write_prvkey): Don't call ac_reset_* + here. + (proc_key_import): But call ac_reset_* here. + (gpg_do_keygen): Load private key for signing. + + * tool/stlinkv2.py (stlinkv2.usb_disconnect): New. + +2012-07-09 Niibe Yutaka + + * src/openpgp.c (cmd_pso): For decryption, return error sooner for + invalid data. + + * tool/stlinkv2.py (stlinkv2.setup_gpio): Fix GPIOB_CRL. + + * test/rsa_keys.py (integer_to_bytes_256): Rename from + integer_to_bytes and it should be exactly 256-byte long. + +2012-07-06 Niibe Yutaka + + * Version 0.21. + * src/usb_desc.c (gnukStringSerial): Updated. + + * boards/FST_01/board.h (VAL_GPIOACRL): Change for SPI flash. + * tool/stlinkv2.py (stlinkv2.setup_gpio): Likewise. + (stlinkv2.spi_flash_init, stlinkv2.spi_flash_select) + (stlinkv2.spi_flash_sendbyte, stlinkv2.spi_flash_read_id): New. + (main): Add SPI flash ROM id check. + +2012-07-05 Niibe Yutaka + + * src/call-rsa.c (rsa_sign, rsa_decrypt): Don't need to setup N. + + * polarssl-0.14.0/library/rsa.c (rsa_check_pubkey) + (rsa_check_privkey): Ifdef-out. + + More tests. + * test/*: Add tests for admin-less mode. + * test/features/990_reset_passphrase.feature: This is now for + admin-less mode. + * test/features/970_key_removal.feature: Ditto. + + * src/openpgp.c (cmd_change_password): Call ac_reset_admin when + admin-less mode. + (cmd_reset_user_password): Likewise. + + * src/ac.c (ac_reset_admin, ac_fini): Clear ADMIN_AUTHORIZED. + + Bug fix. + * src/ac.c (verify_admin): Call s2k with ADMIN_AUTHORIZED. + +2012-07-04 Niibe Yutaka + + Bug fixes. + * src/ac.c (verify_admin_0): Compare PW_LEN and BUF_LEN. + + * src/openpgp-do.c (gpg_do_chks_prvkey): Set do_ptr to NULL before + calling flash_do_write (which might cause GC). + (gpg_do_put_data, gpg_do_write_simple): Likewise. + + * src/openpgp.c (cmd_reset_user_password): Write to + DO_KEYSTRING_PW1. + +2012-07-03 Niibe Yutaka + + * test/features/040_passphrase_change.feature: New. + * test/features/203_passphrase_change.feature: New. + * test/features/210_compute_signature.feature: Rename (was: + 203_compute_signature.feature) + * test/features/211_decryption.feature: Rename (was: + 204_decryption.feature) + +2012-07-02 Niibe Yutaka + + * tool/stlinkv2.py (stlinkv2.__init__): Don't call setAltInterface. + +2012-06-30 Niibe Yutaka + + * src/openpgp.c (s2k): New. + (resetcode_s2k): Remove. + (cmd_reset_user_password, cmd_change_password): Use s2k (was: + sha256 directly or resetcode_s2k). + * src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey): + Likewise. + * src/ac.c (verify_user_0, verify_admin): Likewise. + +2012-06-29 Niibe Yutaka + + * regnual/Makefile: Don't copy usb_lld.c. + +2012-06-28 Niibe Yutaka + + * test/features/204_decryption.feature: New. + * test/features/203_compute_signature.feature: New. + * test/features/202_keygen.feature: New. + * test/features/201_setup_passphrase.feature: New. + * test/features/200_key_removal.feature: New. + + * test/rsa_keys.py (verify_signature): New. + (encrypt_with_pubkey): New. + + * test/gnuk.py (gnuk_token): New method: increment_seq. + (gnuk_token.icc_send_cmd): Handle timeout. + (gnuk_token.cmd_genkey): New. + (gnuk_token.cmd_get_public_key): New. + +2012-06-27 Niibe Yutaka + + * test/features/101_decryption.feature: New. + * test/features/100_compute_signature.feature: New. + + * src/openpgp-do.c (gpg_do_chks_prvkey): Call flash_do_release before + flash_do_write. + (gpg_do_write_prvkey): Bug fix when GC occurs. + + * src/openpgp.c (cmd_change_password): Support resetting to + factory setting of PW3. + + * src/openpgp-do.c (gpg_do_write_prvkey): Don't reset signagure + counter here. + (proc_key_import): But reset here. + Call ac_reset_* when key is imported. + +2012-06-26 Niibe Yutaka + + * test: New. + +2012-06-25 Niibe Yutaka + + * tool/usb_strings.py: New. + +2012-06-22 Niibe Yutaka + + * tool/stlinkv2.py (stlinkv2.blank_check): Add blank check of + Flash ROM. + +2012-06-21 Niibe Yutaka + + * tool/asm-thumb/blank_check.S: New. + +2012-06-20 Niibe Yutaka + + ST-Link/V2 flash ROM writer. + * tool/stlinkv2.py: New. + * tool/asm-thumb/opt_bytes_write.S: New. + * tool/asm-thumb/flash_write.S: New. + +2012-06-19 Niibe Yutaka + + * Version 0.20. + + * src/usb_desc.c (gnukStringSerial): Updated. + +2012-06-18 Niibe Yutaka + + LED display output change. + * src/main.c (MAIN_TIMEOUT_INTERVAL): New. + (LED_TIMEOUT_INTERVAL, etc.): New values. + (main_mode, display_interaction): Remove. + (led_inverted, emit_led): New. + (display_status_code): Use emit_led. + (led_blink): Use LED_* for SPEC. + (main, fatal): New LED display output. + * src/gnuk.h (LED_ONESHOT, LED_TWOSHOTS, LED_SHOW_STATUS) + (LED_START_COMMAND, LED_FINISH_COMMAND, LED_FATAL): New semantics. + (main_thread): Remove. + * src/openpgp-do.c (gpg_do_keygen): Don't touch LED here. + * src/openpgp.c (get_pinpad_input): Call led_blink. + (cmd_pso, cmd_internal_authenticate): Don't touch LED here. + (GPGthread): Call led_blink. + * src/pin-cir.c (pinpad_getline): Change arg of led_blink. + * src/pin-dnd.c (pinpad_getline): Ditto. + * src/usb-icc.c (icc_handle_timeout): Ditto. + (icc_send_status): Call led_blink. + * src/usb_ctrl.c (gnuk_usb_event): Don't touch LED here. + +2012-06-16 Niibe Yutaka + + Use SHA256 format for "external authenticate". + * tool/gnuk_upgrade.py (gpg_sign): SHA256 sign by "SCD PKAUTH". + (main): Not specify keygrip, but always use key for authentication. + * src/call-rsa.c (rsa_verify): It is SHA256 format (was: SHA1). + * src/openpgp.c (cmd_get_challenge): Don't add chip-id prefix. + (cmd_external_authenticate): Likewise. + +2012-06-15 Niibe Yutaka + + * src/random.c (random_bytes_free): Clear out random bytes. + + More protection improvements. + * src/random.c (RANDOM_BYTES_LENGTH): It's 32 now (was: 16). + * src/gnuk.h (struct key_data_internal): Remove check, random, + magic. Add checksum. + (struct prvkey_data): Remove crm_encrypted. Add iv and + checksum_encrypted. + * src/openpgp-do.c (encrypt, decrypt): Add IV argument. + (encrypt_dek, decrypt_dek): New. It's in ECB mode. + (compute_key_data_checksum): New. + (gpg_do_load_prvkey): Handle initial vector and checksum. + Use decrypt_dek to decrypt DEK. Clear DEK after use. + (calc_check32):Remove. + (gpg_do_write_prvkey): Use encrypt_dek to encrypt DEK. + (gpg_do_chks_prvkey): Likewise. + + * polarssl-0.14.0/include/polarssl/aes.h (aes_crypt_cbc) + * polarssl-0.14.0/library/aes.c (aes_crypt_cbc): ifdef-out. + + * src/configure (--enable-pinpad): Deprecate DND. + +2012-06-14 Niibe Yutaka + + Protection improvement. + * src/openpgp.c (resetcode_s2k): New. + (cmd_reset_user_password): Use resetcode_s2k. + * src/openpgp-do.c (proc_resetting_code): Likewise. + + * src/sha256.c (sha256_finish): Clear out CTX at the end. + + * src/call-rsa.c (rsa_sign, rsa_decrypt, rsa_verify): Use + mpi_lset (was: mpi_read_string). + * polarssl-0.14.0/library/bignum.c (mpi_get_digit) + (mpi_read_string): ifdef-out. + + KDF is now SHA-256 (was: SHA1). + * src/sha256.c: New file. Based on the implementation by Dr Brian + Gladman. + * src/openpgp.c (cmd_change_password, cmd_reset_user_password): + Use sha256. + * src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey): Likewise. + * src/ac.c (verify_user_0, calc_md, verify_admin): Likewise. + * src/crypt.mk (CRYPTSRC): Add sha256.c, removing sha1.c. + * src/gnuk.h (KEYSTRING_MD_SIZE): It's 32 for SHA-256. + +2012-06-13 Niibe Yutaka + + Bug fixes. + * src/main.c (display_interaction): Assign to main_mode. + * src/openpgp.c (cmd_change_password): Bug fix for admin less mode + to admin full mode. Variable who_old should be admin_authorized. + + Key generation is configure option. + * src/configure (keygen): Add --enable-keygen option. + * src/Makefile.in (UDEFS): Add definition of KEYGEN_SUPPORT. + * src/call-rsa.c [KEYGEN_SUPPORT] (rsa_genkey): Conditionalize. + * src/random.c [KEYGEN_SUPPORT] (random_byte): Ditto. + * src/openpgp.c [KEYGEN_SUPPORT] (cmd_pgp_gakp): Ditto. + * src/openpgp-do.c [KEYGEN_SUPPORT] (gpg_do_keygen): Ditto. + * polarssl-0.14.0/include/polarssl/config.h: Ditto. + * polarssl-0.14.0/library/bignum.c [POLARSSL_GENPRIME] + (mpi_inv_mod): Unconditionalize. + +2012-06-08 Niibe Yutaka + + * polarssl-0.14.0/library/bignum.c (mpi_cmp_mpi): Bug fix. + Though it doesn't matter for Gnuk usage. + + Emit LED light while computation (or asking user input). + * src/usb-icc.c (icc_handle_timeout): Call led_blink. + * src/openpgp.c (cmd_pso, cmd_internal_authenticate): Call + LED_WAIT_MODE, LED_STATUS_MODE to show "it's under computation". + * src/openpgp-do.c (gpg_do_keygen): Ditto. + * src/gnuk.h (LED_WAIT_MODE): Rename (was: LED_INPUT_MODE). + * src/main.c (display_interaction): Change the behavior of LED, + now, it's mostly ON (was: mostly OFF). + +2012-06-07 Niibe Yutaka + + * src/openpgp.c (cmd_internal_authenticate): Add check for input + length. + + Implement key generation. + * src/openpgp.c (cmd_pgp_gakp): Call gpg_do_keygen. + * src/openpgp-do.c (proc_key_import): Call with modulus = NULL. + (gpg_do_keygen): New function. + (gpg_reset_digital_signature_counter): New function. + (gpg_do_write_prvkey): New argument MODULUS. Call + gpg_reset_digital_signature_counter. + * src/call-rsa.c (rsa_genkey): New function. + * src/random.c (random_byte): New function. + + PolarSSL modification. + * polarssl-0.14.0/library/rsa.c (rsa_gen_key): Don't set D, DP, + DQ, and QP. It's only for key generation. + * polarssl-0.14.0/library/rsa.c (rsa_gen_key, rsa_pkcs1_encrypt): + Change f_rng function return type. + * polarssl-0.14.0/include/polarssl/rsa.h: Likewise. + * polarssl-0.14.0/library/bignum.c (mpi_is_prime, mpi_gen_prime): + Change f_rng function return type. + * polarssl-0.14.0/include/polarssl/bignum.h: Likewise. + +2012-06-06 Niibe Yutaka + + * Version 0.19. + + * src/usb_desc.c (gnukStringSerial): Updated. + + * regnual/regnual.c (fetch): Better implementation. + +2012-06-05 Niibe Yutaka + + Firmware update key handling. + * tool/gnuk_put_binary.py (GnukToken.cmd_get_response): Handle + larger data such as card holder certificate. + (GnukToken.cmd_write_binary): Bug fix for cert do write. + (GnukToken.cmd_read_binary): New. + (main): Support firmware update key. + + Take advantage of the Thumb-2 "rbit" instruction. + * regnual/regnual.c (fetch): Reverse bits. + * src/usb_ctrl.c (rbit): New. Deleted reverse32. + (download_check_crc32): Use rbit. + * tool/gnuk_upgrade.py (crc32): Just use binascii.crc32. + (crctab): Remove. + +2012-06-04 Niibe Yutaka + + Card holder certificate data object bug fixes. + * tool/gnuk_put_binary_libusb.py (gnuk_token.cmd_get_response): + Handle larger data such as card holder certificate. + * src/flash.c (flash_write_binary): Bug fix. Call + flash_check_blank with p + offset. + * src/gnuk.h (FLASH_CH_CERTIFICATE_SIZE): Define here (was: flash.c). + + Implement CRC32 check for firmware update. + * src/usb_ctrl.c (download_check_crc32): New. + * regnual/regnual.c (calc_crc32): New. + (regnual_ctrl_write_finish): Call calc_crc32. + * tool/gnuk_upgrade.py (crc32): New. + (regnual.download): Check crc32code. + + * regnual/regnual.c (regnual_ctrl_write_finish): Bug fix. + +2012-06-01 Niibe Yutaka + + Support firmware update with public key authentication. + * tool/gnuk_upgrade.py (gpg_sign): New. + * tool/gnuk_put_binary_libusb.py (main): Support firmware update + key registration. + + Update of reGNUal. + * regnual/regnual.c (main): Follow the change of usb_lld_init. + (regnual_config_desc): Include interface descriptor. + (usb-strings.c.inc): Change the file name. + * regnual/Makefile (regnual.o): Depend on sys.h. + * src/configure (usb-strings.c.inc): ifdef-out + gnuk_revision_detail and gnuk_config_options (for reGNUal). + * src/usb_desc.c (USB_STRINGS_FOR_GNUK): Define. + + USB bug fixes. + * src/usb_ctrl.c (gnuk_usb_event): Bug fix for handling + USB_EVENT_CONFIG. Do nothing when current_conf == value. + * src/usb_lld.c (std_clear_feature): Bug fix. Always clear DTOG. + (usb_lld_init): New argument for FEATURE. + +2012-05-31 Niibe Yutaka + + * polarssl-0.14.0/library/rsa.c (rsa_pkcs1_verify): BUF size is + 256 (was: 1024). + * src/call-rsa.c (rsa_verify): It's SIG_RSA_SHA1. + * src/openpgp.c (cmd_external_authenticate): Follow the change of + rsa_verify. + + Support "firmware update" keys. + * src/flash.c (flash_write_binary): Support update keys. + * src/gnuk.h (FILEID_UPDATE_KEY_0, FILEID_UPDATE_KEY_1) + (FILEID_UPDATE_KEY_2,FILEID_UPDATE_KEY_3): New. + * src/gnuk.ld.in (_updatekey_store): New. + * src/openpgp.c (FILE_EF_UPDATE_KEY_0, FILE_EF_UPDATE_KEY_1) + (FILE_EF_UPDATE_KEY_2, FILE_EF_UPDATE_KEY_3): New. + (gpg_get_firmware_update_key): New. + (cmd_read_binary): Support update keys and certificate. + (modify_binary): New. + (cmd_update_binary, cmd_write_binary): Use modify_binary. + (cmd_external_authenticate): Support up to four keys. + + Version string of system service is now USB string. + * src/sys.h (unique_device_id): Define here, not as system + service. + * src/sys.c (sys_version): Version string for system service. + * src/usb_desc.c (String_Descriptors): Add sys_version. + * src/usb_conf.h (NUM_STRING_DESC): 7 (was: 6). + * src/gnuk.ld.in (.sys.version): New section. + +2012-05-30 Niibe Yutaka + + * src/openpgp.c (CHALLENGE_LEN): New. + (cmd_external_authenticate): Authentication by response with + public key. + (cmd_get_challenge): 16-byte is enough for challenge. + +2012-05-29 Niibe Yutaka + + * src/call-rsa.c (rsa_verify): New function. + + * polarssl-0.14.0/include/polarssl/rsa.h (rsa_pkcs1_verify) + * polarssl-0.14.0/library/rsa.c (rsa_pkcs1_verify): Fix API. + + * src/usb_conf.h (NUM_STRING_DESC): Incremented to 6 (was: 4). + * src/configure: Generate strings for revision detail and config + options. + * src/usb_desc.c (gnuk_revision_detail, gnuk_config_options): New. + + * src/main.c (main) [DFU_SUPPORT]: Kill DFU and install .sys. + + * src/config.h.in (FLASH_PAGE_SIZE): New. + * src/configure: Support FLASH_PAGE_SIZE for config.h + * boards/*/board.h (FLASH_PAGE_SIZE): Remove. + * src/flash.c (FLASH_PAGE_SIZE): Remove. + + * src/sys.c (reset): Don't depend if DFU_SUPPORT or not. + (flash_erase_all_and_exec): Rename and change the argument. + * src/gnuk.ld.in (__flash_start__): Real flash ROM address, + regardless of DFU_SUPPORT. + * src/main.c (main): Call flash_erase_all_and_exec with SRAM + address. + + * polarssl-0.14.0/library/aes.c (FT0, FT1, FT2): Specify sections + in detail, so that addresses won't be affected by compiler. + * src/gnuk.ld.in (.sys): Define sections in detail. + + * boards/STBEE_MINI/board.h (SET_USB_CONDITION, GPIO_USB) + (IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED) + (FLASH_PAGE_SIZE): New. + * boards/STBEE_MINI/board.c (USB_Cable_Config, set_led): Remove. + + * boards/STBEE/board.h (SET_USB_CONDITION, GPIO_USB, IOPORT_USB) + (SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New. + * boards/STBEE/board.c (USB_Cable_Config, set_led): Remove. + + * boards/CQ_STARM/board.h (SET_USB_CONDITION) + (SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New. + * boards/CQ_STARM/board.c (USB_Cable_Config, set_led): Remove. + +2012-05-28 Niibe Yutaka + + * boards/*/board.c (hwinit0): Removed... + * boards/common/hwinit.c (hwinit0): ... and define here. + (hwinit0) [DFU_SUPPORT]: Don't set SCB->VTOR here. + * src/sys.c (reset) [DFU_SUPPORT]: Set SCB->VTOR here. + (flash_write): Range check. + + * polarssl-0.14.0/library/aes.c (FT0, FT1, FT2): Specify the + section ".sys", so that we will have more room for flash ROM. + * src/gnuk.ld.in (.sys): Add alignment settings. + + * tool/gnuk_upgrade.py (main): First 4096-byte of Gnuk is system + block. Don't send it to reGNUal. + + * regnual/sys.c (entry): Fix clearing BSS. It is called with all + interrupts disabled. + + * regnual/regnual.ld (_flash_start): It's 0x08001000 now, because + there is system block now (was: 0x08000000). + +2012-05-26 Niibe Yutaka + + * src/sys.c (reset): Set SCR->VCR here. + +2012-05-25 Niibe Yutaka + + * src/gnuk.ld.in (.sys): New section. + + * boards/OLIMEX_STM32_H103/board.h (SET_USB_CONDITION, GPIO_USB) + (IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED) + (FLASH_PAGE_SIZE): New. + * boards/OLIMEX_STM32_H103/board.c (USB_Cable_Config, set_led): + Remove. + + * boards/STM32_PRIMER2/board.h (SET_USB_CONDITION, GPIO_USB) + (IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED) + (FLASH_PAGE_SIZE): New. + * boards/STM32_PRIMER2/board.c (USB_Cable_Config, set_led): + Remove. + + * boards/FST_01_00/board.h (SET_USB_CONDITION, GPIO_USB) + (IOPORT_USB, SET_LED_CONDITION, GPIO_LED, IOPORT_LED) + (FLASH_PAGE_SIZE): New. + * boards/FST_01_00/board.c (USB_Cable_Config, set_led): Remove. + + * boards/FST_01/board.h (SET_USB_CONDITION, GPIO_USB, IOPORT_USB) + (SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New. + * boards/FST_01/board.c (USB_Cable_Config, set_led): Remove. + + * regnual/sys-stm8s-discovery.h, sys-stbee.h: Remove. + + * boards/STM8S_DISCOVERY/board.h (SET_USB_CONDITION) + (SET_LED_CONDITION, GPIO_LED, IOPORT_LED, FLASH_PAGE_SIZE): New. + * boards/STM8S_DISCOVERY/board.c (USB_Cable_Config, set_led): + Remove. + + * regnual/Makefile: Add -I ../src to CFLAGS. + + * regnual/regnual.ld (vector): New. + + * regnual/sys.c: Remove implementation, but jump to vector by sys.h. + + * src/Makefile.in: Follow change of files. + + * src/configure: Undo changes of 2012-05-22. + + * boards/common/hw_config.c: Remove. Mov function to sys.c. + * src/flash.c: Move functions to sys.c. + * src/sys.c: New. + + * src/main.c (main): Call flash_mass_erase_and_exec. + + * src/usb_lld.c: Include sys.h. + + * src/usb_lld_sys.c: Remove. Move interrupt handler to... + * src/usb_ctrl.c: ... this file. + + * regnual/sys.c (clock_init, gpio_init, flash_unlock): Removed. + (entry): Rename (was: reset). + +2012-05-24 Niibe Yutaka + + * src/main.c (good_bye): Care LSB of function pointer. + (flash_mass_erase_and_exec): Implemented in C. + +2012-05-23 Niibe Yutaka + + * regnual/sys-stm8s-discovery.h: New. + + * src/main.c (flash_mass_erase_and_exec, good_bye): New. + (main): Call good_bye. + + * tool/gnuk_upgrade.py (regnual.protect): New. + (main): Call regnual.protect(). + + * regnual/regnual.c (regnual_setup): Don't call flash_write here. + (regnual_ctrl_write_finish): But call here. + (USB_REGNUAL_RESULT): New. + + * regnual/sys.c (flash_protect): New. + +2012-05-22 Niibe Yutaka + + * src/configure (../regnual/sys.h): Create symblic link. + + * src/usb_ctrl.c: Rename (was: usb_prop.c). + + * regnual/types.h, regnual/sys.c, regnual/regnual.ld: New. + * regnual/regnual.c, regnual/Makefile: New. + * regnual/sys-stbee.h: New. + + * src/usb_lld.c: Support FREE_STANDING environment as well as + under ChibiOS/RT. + (usb_lld_init): Call usb_lld_sys_init. Don't call user defined + method. Call usb_lld_set_configuration. + (usb_lld_shutdown): Call usb_lld_sys_shutdown. + (Vector90): Move to usb_lld_sys.c. + (usb_interrupt_handler): Export to global. + + * src/usb_lld_sys.c: New. + + * src/usb_prop.c (Device_Method): Remove gnuk_device_init. + (gnuk_device_init): Remove. + +2012-05-19 Niibe Yutaka + + * src/usb_lld.c (handle_datastage_in): Bug fix, erable RX when + sending ZLP. It will be possible to get OUT transaction soon + after IN transaction. + +2012-05-18 Niibe Yutaka + + * src/usb_lld.c (handle_datastage_out): Fix rx copying. + (handle_setup0): Bug fix not stalling TX, it will be possible + to go IN transaction, soon after OUT transaction. + + * src/usb_lld.h (USB_SETUP_SET, USB_SETUP_GET): New. + (usb_device_method.ctrl_write_finish): New. + (usb_device_method.setup): Merge setup_with_data, and + setup_with_nodata. + + * src/usb_lld.c (usb_lld_shutdown, usb_lld_prepare_shutdown): New. + (handle_setup0): Call ->setup. + (handle_in0): Call ->ctrl_write_finish. + + * src/usb_prop.c (vcom_port_data_setup): Merge + vcom_port_setup_with_nodata. + (download_check_crc32): New. + (gnuk_setup): Merge gnuk_setup_with_data and + gnuk_setup_with_nodata. + (gnuk_ctrl_write_finish): New. + +2012-05-17 Niibe Yutaka + + * tool/gnuk_upgrade.py: New tool. + + * src/gnuk.h (ICC_STATE_EXITED, ICC_STATE_EXEC_REQUESTED): New. + + * src/openpgp.c (INS_EXTERNAL_AUTHENTICATE) + (cmd_external_authenticate): New. + (INS_GET_CHALLENGE, cmd_get_challenge): New. + + * src/usb-icc.c (USBthread): Finish the thread with + ICC_STATE_EXITED, after EXTERNAL_AUTHENTICATE. + + * src/usb_prop.c (gnuk_setup_endpoints_for_interface): Add STOP + argument. + (gnuk_usb_event): Disable all endpoints when configure(0). + (vcom_port_data_setup): Check direction and support + USB_CDC_REQ_SET_LINE_CODING. + (vcom_port_setup_with_nodata): Check direction. + (gnuk_setup_with_data): Check direction and add FSIJ_GNUK device + requests. + (gnuk_setup_with_nodata): Likewise. + + * src/usb_lld.c (LAST_OUT_DATA): Remove. + (handle_datastage_out): Cleanup and call st103_ep_set_rxtx_status. + (handle_datastage_in): Call st103_ep_set_rxtx_status and + st103_ep_set_tx_status. + (handle_setup0): Likewise. + (handle_out0): Remove LAST_OUT_DATA. + (std_none, std_get_status, std_clear_feature, std_set_feature) + (std_set_address, std_get_descriptor, std_get_configuration) + (std_set_configuration, std_get_interface, std_set_interface): + Check direction. + (handle_setup0): Add length for setup_with_data. + +2012-05-16 Niibe Yutaka + + * tool/gnuk_put_binary.py (main): Fix fileid. + * tool/gnuk_put_binary_libusb.py: Ditto. + + * src/openpgp.c (FILE_EF_RANDOM): Remove. + (cmd_update_binary, cmds): ifdef CERTDO_SUPPORT. + (cmd_write_binary): Fix fileid. + + * src/flash.c (flash_check_blank): Always enable. + (flash_erase_binary): ifdef CERTDO_SUPPORT. + (flash_write_binary): Call flash_check_blank. + +2012-05-15 Niibe Yutaka + + * Version 0.18. + + * src/usb_desc.c (gnukStringSerial): Updated. + + * src/main.c (EP3_IN_Callback, EP5_OUT_Callback): Move from + usb_endp.c. + + * src/usb_endp.c: Remove. + +2012-05-14 Niibe Yutaka + + * tool/gnuk_remove_keys.py: New. + + * src/openpgp-do.c (proc_key_import): Fix checking extended header. + + * src/hardclock.c: Remove. + + * src/usb_prop.c (MSC_INTERFACE_NO): New. + (gnuk_setup_endpoints_for_interface): Cleanup with MSC_INTERFACE_NO. + (gnuk_setup_with_data, gnuk_setup_with_nodata): Likewise. + + * src/usb-msc.c: Rename from usb_msc.c. + + * src/usb-msc.h: Rename from usb_msc.h. + + * src/Makefile.in: Follow the rename of usb-msc.c and remove of + hardclock.c. + + * src/pin-dnd.c, src/usb_prop.c: Follow the rename of usb-msc.h. + +2012-05-12 Niibe Yutaka + + * src/usb_msc.c (ep6_out): Rename (was: ep7_out). + (usb_start_receive): Use ep6_out and ENDP6. + (EP6_OUT_Callback): Rename (was: EP7_OUT_Callback). + Use ep6_out and ENDP6. + (msc_handle_command): Use ep6_out and ENDP6. + + * src/main.c (main): Wait USB reset. + + * src/usb-icc.c (EP1_OUT_Callback): Rename from EP2_OUT_Callback. + (USBthread): Use ENDP1 for both of epi_init and epo_init. + + * src/usb_conf.h (ENDP1_RXADDR, ENDP2_TXADDR, ENDP6_RXADDR): New. + (ENDP3_TXADDR, ENDP4_TXADDR, ENDP5_RXADDR): New value. + (ENDP7_RXADDR): Remove. + + * src/usb_desc.c (gnukConfigDescriptor): Use endpoint OUT1 (was + IN2), endpoint OUT6 (IN7). + + * src/usb_prop.c (gnuk_setup_endpoints_for_interface): Use ENDP1 + and ENDP6 for both directions. + +2012-05-11 Niibe Yutaka + + * src/configure (--vidpid): New mandatory option. + + * GNUK_USB_DEVICE_ID: New file. + + * src/usb_desc.c (gnukDeviceDescriptor): Include + usb-vid-pid-ver.c.inc. + (gnukStringVendor, gnukStringProduct): Remove. It's in the + file, usb-string-vender-product.c.inc. + + * src/Makefile.in (distclean): Delete *.inc. + + * src/usb_prop.c (vcom_port_setup_with_nodata) Rename. + (vcom_port_data_setup): Rename and fix return value. + + * src/usb-cdc.h (VIRTUAL_COM_PORT_DATA_SIZE) + (VIRTUAL_COM_PORT_INT_SIZE): New. + + * src/main.c (#include): Add usb-cdc.h. + * src/usb_desc.c (#include): Add usb-cdc.h. + * src/usb_endp.c (#include): Add usb_lld.h. + + * src/configure ($help): Add FST_01. + +2012-05-10 Niibe Yutaka + + * STM32_USB-FS-Device_Driver, Virtual_COM_Port: Remove. + + * src/usb_lld.c (#include): Don't include usb_lib.h. + (RECIPIENT, REG_BASE PMA_ADDR, CNTR, ISTR, FNR, DADDR, BTABLE) + (ISTR_CTR, ISTR_DOVR, ISTR_ERR, ISTR_WKUP, ISTR_SUSP, ISTR_RESET) + (ISTR_SOF, ISTR_ESOF, ISTR_DIR, ISTR_EP_ID, CLR_CTR, CLR_DOVR) + (CLR_ERR, CLR_WKUP, CLR_SUSP, CLR_RESET, CLR_SOF, CLR_ESOF) + (CNTR_CTRM, CNTR_DOVRM, CNTR_ERRM, CNTR_WKUPM, CNTR_SUSPM) + (CNTR_RESETM, CNTR_SOFM, CNTR_ESOFM, CNTR_RESUME, CNTR_FSUSP) + (CNTR_LPMODE, CNTR_PDWN, CNTR_FRES, DADDR_EF, DADDR_ADD) + (EP_CTR_RX, EP_DTOG_RX, EPRX_STAT, EP_SETUP, EP_T_FIELD, EP_KIND) + (EP_CTR_TX, EP_DTOG_TX, EPTX_STAT, EPADDR_FIELD, EPREG_MASK) + (EP_TX_DIS, EP_TX_STALL, EP_TX_NAK, EP_TX_VALID, EPTX_DTOG1) + (EPTX_DTOG2, EP_RX_DIS, EP_RX_STALL, EP_RX_NAK, EP_RX_VALID) + (EPRX_DTOG1, EPRX_DTOG2): New. Compatible to ST's USB-FS-Device_Lib. + (CH_IRQ_HANDLER): Call usb_interrupt_handler (was: USB_Istr). + (EP1_IN_Callback, EP2_IN_Callback, EP3_IN_Callback) + (EP4_IN_Callback, EP5_IN_Callback, EP6_IN_Callback) + (EP7_IN_Callback, EP1_OUT_Callback, EP2_OUT_Callback) + (EP3_OUT_Callback, EP4_OUT_Callback, EP5_OUT_Callback) + (EP6_OUT_Callback, EP7_OUT_Callback): New. Implement here. + Compatible to ST's USB-FS-Device_Lib. + (USB_MAX_PACKET_SIZE): New. + (GET_STATUS, CLEAR_FEATURE, RESERVED1, SET_FEATURE, RESERVED2) + (SET_ADDRESS, GET_DESCRIPTOR, SET_DESCRIPTOR, GET_CONFIGURATION) + (SET_CONFIGURATION, GET_INTERFACE, SET_INTERFACE) + (SYNCH_FRAME,TOTAL_REQUEST): New for USB control transfer. + (enum CONTROL_STATE): New for state machine of control pipe. + (enum FEATURE_SELECTOR): New. + (struct DATA_INFO, struct CONTROL_INFO, struct DEVICE_INFO): New. + (ctrl_p, dev_p, data_p, Control_Info, Device_Info, Data_Info): + New. + (usb_lld_stall_tx, usb_lld_stall_rx) + (usb_lld_tx_data_len, usb_lld_txcpy, usb_lld_tx_enable) + (usb_lld_write, usb_lld_rx_enable, usb_lld_rx_data_len) + (usb_lld_rxcpy): Move from usb_lld.h and not inline. + (usb_lld_reset, usb_lld_setup_endpoint) + (usb_lld_set_configuration, usb_lld_current_configuration) + (usb_lld_set_feature, usb_lld_set_data_to_send): New. + (usb_lld_to_pmabuf, usb_lld_from_pmabuf): Clean up. + (usb_lld_init): New implementation. + (st103_set_btable, st103_get_istr, st103_set_istr, st103_set_cntr) + (st103_set_daddr, st103_set_epreg, st103_get_epreg) + (st103_set_tx_addr, st103_get_tx_addr, st103_set_tx_count) + (st103_get_tx_count, st103_set_rx_addr, st103_get_rx_addr) + (st103_set_rx_buf_size, st103_get_rx_count, st103_ep_clear_ctr_rx) + (st103_ep_clear_ctr_tx, st103_ep_set_rxtx_status) + (st103_ep_set_rx_status, st103_ep_get_rx_status) + (st103_ep_set_tx_status, st103_ep_get_tx_status) + (st103_ep_clear_dtog_rx, st103_ep_clear_dtog_tx): New lower-level + functions for USB related registers access. + (usb_interrupt_handler, usb_handle_transfer) + (handle_datastage_out, handle_datastage_in, handle_setup0) + (handle_in0, handle_out0) + (std_none, std_get_status, std_clear_feature, std_set_feature, + std_set_address, std_get_descriptor, std_get_configuration, + std_set_configuration, std_get_interface, std_set_interface) + (std_request_handler): New USB stack implementation. + + * src/usb_lld.h (usb_lld_stall_tx, usb_lld_stall_rx) + (usb_lld_tx_data_len, usb_lld_txcpy, usb_lld_tx_enable) + (usb_lld_write, usb_lld_rx_enable, usb_lld_rx_data_len) + (usb_lld_rxcpy): Those are not inline functions anymore. + (USB_DEVICE_DESCRIPTOR_TYPE, USB_CONFIGURATION_DESCRIPTOR_TYPE) + (USB_STRING_DESCRIPTOR_TYPE, USB_INTERFACE_DESCRIPTOR_TYPE) + (USB_ENDPOINT_DESCRIPTOR_TYPE, STANDARD_ENDPOINT_DESC_SIZE) + (ENDP0, ENDP1, ENDP2, ENDP3, ENDP4, ENDP5, ENDP6, ENDP7) + (EP_BULK, EP_CONTROL, EP_ISOCHRONOUS, EP_INTERRUPT) + (DEVICE_RECIPIENT, INTERFACE_RECIPIENT, ENDPOINT_RECIPIENT) + (ENDPOINT_RECIPIENT, OTHER_RECIPIENT) + (DEVICE_DESCRIPTOR, CONFIG_DESCRIPTOR, STRING_DESCRIPTOR) + (INTERFACE_DESCRIPTOR, ENDPOINT_DESCRIPTOR) + (REQUEST_TYPE, STANDARD_REQUEST, CLASS_REQUEST, VENDOR_REQUEST) + (USB_UNSUPPORT, USB_SUCCESS) + (USB_EVENT_RESET, USB_EVENT_ADDRESS, USB_EVENT_CONFIG) + (USB_EVENT_SUSPEND, USB_EVENT_WAKEUP, USB_EVENT_STALL) + (USB_SET_INTERFACE, USB_GET_INTERFACE, USB_QUERY_INTERFACE) + (UNCONNECTED, ATTACHED, POWERED, SUSPENDED, ADDRESSED) + (CONFIGURED, USB_Cable_Config): New. Compatible to ST's + USB-FS-Device_Lib. + (struct Descriptor, struct usb_device_method) + (Device_Descriptor, Config_Descriptor, String_Descriptors) + (STM32_USB_IRQ_PRIORITY, bDeviceState, Device_Method) + (usb_lld_init, usb_lld_reset, usb_lld_setup_endpoint) + (usb_lld_set_configuration, usb_lld_current_configuration) + (usb_lld_set_feature, usb_lld_set_data_to_send): New API. + + * src/usb_prop.c(#include): Only include usb_lld.h for USB. + (SetEPRxCount_allocated_size): Remove. + (struct line_coding, line_coding, Virtual_Com_Port_Data_Setup) + (Virtual_Com_Port_NoData_Setup): Add from usb-cdc-vport.c. + (gnuk_device_init, gnuk_device_reset, gnuk_setup_with_data) + (gnuk_setup_with_nodata): Follow the API change of USB stack. + (gnuk_setup_endpoints_for_interface, gnuk_get_descriptor) + (gnuk_usb_event, gnuk_interface): New. + (gnuk_device_SetConfiguration, gnuk_device_SetInterface) + (gnuk_device_SetDeviceAddress, gnuk_device_Status_In) + (gnuk_device_Status_Out, gnuk_device_GetDeviceDescriptor) + (gnuk_device_GetConfigDescriptor, gnuk_device_GetStringDescriptor) + (gnuk_device_Get_Interface_Setting, gnuk_clock_frequencies) + (gnuk_data_rates, msc_lun_info, Device_Table) + (User_Standard_Requests): Remove. + (Device_Method): Replace Device_Property. + + * src/usb_msc.c (#include): Only include usb_lld.h for USB. + + * src/usb_endp.c (#include): Only include usb_lld.h for USB. + (EP5_OUT_Callback): Follow the API change of USB stack. + + * src/usb_desc.c (#include): Only include usb_lld.h for USB. + Add usb_conf.h. + (Device_Descriptor, Config_Descriptor): Follow the API change + of USB stack. + (String_Descriptors): New, rename from String_Descriptor. + + * src/usb_conf.h (EP_NUM, BTABLE_ADDRESS, IMR_MSK): Remove. + (NUM_STRING_DESC): Add. + + * src/usb-icc.c (#include): Only include usb_lld.h for USB. + + * src/usb-cdc-vport.c, src/usb_prop.h: Remove. + + * src/stmusb.mk, src/vcomport.mk: Remove. + + * src/main.c (#include): Only include usb_lld.h for USB. + (main): Remove call to USB_Init. + + * src/Makefile.in (include): Remove stmusb.mk, vcomport.mk. + (VCOMSRC) [ENABLE_VCOMPORT]: Add. + (INCDIR): Remove STMUSBINCDIR and VCOMDIR. + + * boards/common/hw_config.c (Enter_LowPowerMode) + (Leave_LowPowerMode): Remove. + +2012-02-02 Niibe Yutaka + + * Version 0.17. + + * src/usb_desc.c (gnukStringSerial): Updated. + (gnukConfigDescriptor): Short APDU only. + + * tool/gnuk_put_binary.py (cmd_get_response): New. + (cmd_select_openpgp, cmd_get_data): Call cmd_get_response. + +2012-01-30 Niibe Yutaka + + * src/usb-icc.c (struct ccid): Add chained_cls_ins_p1_p2. + (end_cmd_apdu_head, icc_cmd_apdu_data, icc_handle_data): Add checking + CMD APDU head for command chaining. + +2012-01-20 Niibe Yutaka + + Short APDU only CCID driver. + * STM32_USB-FS-Device_Driver/src/usb_core.c (DataStageOut) + (DataStageIn): Use usb_lld_to_pmabuf and usb_lld_from_pmabuf. + + * src/configure (CERTDO_SUPPORT): Comment fix. + + * src/gnuk.h (struct adpu): expected_res_size has type uint16_t. + (MAX_CMD_APDU_DATA_SIZE, MAX_RES_APDU_DATA_SIZE): New. + (MAX_CMD_APDU_SIZE, MAX_RES_APDU_SIZE, USB_BUF_SIZE): Remove. + (icc_state_p): New. + (set_res_sw): Rename from set_res_apdu. + + * src/call-rsa.c (rsa_decrypt): Use MAX_RES_APDU_DATA_SIZE. + + * src/openpgp.c (set_res_sw): Rename from set_res_apdu. + * src/openpgp.h: Use set_res_sw. + + * src/main.c: Handle icc_state_p. + + * src/openpgp-do.c (historical_bytes): command chaining but short + APDU only. + (extended_capabilities): Change for short APDU only. + + * src/usb-icc.c (USB_BUF_SIZE): Define here (was in gnuk.h). + (struct ep_in, epi_init, struct ep_out, epo_init, endpoint_out) + (endpoint_in, icc_state_p, struct ccid, APDU_STATE_WAIT_COMMAND) + (APDU_STATE_COMMAND_CHAINING, APDU_STATE_COMMAND_RECEIVED) + (APDU_STATE_RESULT, APDU_STATE_RESULT_GET_RESPONSE, ccid_reset) + (ccid_init, CMD_APDU_HEAD_SIZE, apdu_init, notify_tx, no_buf) + (set_sw1sw2, get_sw1sw2, notify_icc, end_icc_rx, end_abdata) + (end_cmd_apdu_head, end_nomore_data, end_cmd_apdu_data) + (nomore_data, INS_GET_RESPONSE, icc_cmd_apdu_data, icc_abdata) + (icc_send_data_block_0x9000, icc_send_data_block_gr, ccid): New. + (icc_data_size, icc_seq, icc_next_p, icc_chain_p, icc_tx_size) + (icc_thread, icc_state, gpg_thread, ICC_RESPONSE_MSG_DATA_SIZE): + Remove. + (EP1_IN_Callback): Rewrite using epi. + (EP2_OUT_Callback): Rewrite using epo. + (icc_prepare_receive): Rewrite using epo and struct ccid. + (ATR): Change ofr short APDU only. + (icc_error, icc_power_on, icc_send_status, icc_power_off) + (icc_send_data_block, icc_send_params, icc_handle_data) + (icc_handle_timeout, USBthread): Rewrite using struct ccid. + + * src/usb_desc.c (gnukConfigDescriptor): dwFeatures: Short APDU + level, dwMaxCCIDMessageLength: 271. + + * src/usb_lld.c (usb_lld_to_pmabuf, usb_lld_from_pmabuf): New. + * src/usb_lld.h (usb_lld_txcpy, void usb_lld_write) Use + usb_lld_to_pmabuf. + (usb_lld_rxcpy): Use usb_lld_from_pmabuf. + + * src/stmusb.mk (usb_mem.c): Remove. + + * gnuk_put_binary.py (cmd_select_openpgp): No response APDU data. + (cmd_verify, cmd_write_binary): Send short APDU. + (__main__): Remove RANDOM_NUMBER_BITS support. + + Bug fix for CERTDO_SUPPORT. + * src/gnuk.ld.in: Add missing alignment for _data_pool (when no + CERTDO_SUPPORT). + +2012-01-19 Niibe Yutaka + + * src/usb-icc.c (icc_handle_data): Handle the case when it only + sends 0x90 and 0x00 correctly. + + * src/openpgp-do.c (gpg_do_get_data): Fix res_apdu_data_len. + +2012-01-18 Niibe Yutaka + + Clean up API between application layer and CCID layer. + * tool/gnuk_put_binary.py, gnuk_put_binary_libusb.py: Don't append + 0x9000 at the data, any more. + * src/usb-icc.c (icc_data_size, icc_buffer, icc_seq): Make them + internal. + (res_APDU_size, res_APDU_pointer): Removed. + (icc_handle_data, USBthread): Follow new API of struct apdu. + * src/call-rsa.c (rsa_sign, rsa_decrypt): Likewise. + * src/openpgp.c (CLS, INS, P1, P2): New. + (set_res_apdu, cmd_verify, cmd_change_password) + (cmd_reset_user_password, cmd_put_data, cmd_pgp_gakp) + (cmd_read_binary, cmd_select_file, cmd_pso) + (cmd_internal_authenticate, cmd_update_binary, cmd_write_binary) + (process_command_apdu, GPGthread): Follow new API of struct apdu. + * src/openpgp-do.c (gpg_do_get_data, gpg_do_public_key): Follow + new API of struct apdu. + * src/gnuk.h (struct apdu, apdu): New. + (cmd_APDU, icc_data_size, cmd_APDU_size, icc_buffer): Removed. + (res_APDU, res_APDU_size): Use members of struct apdu. + +2012-01-16 Niibe Yutaka + + Adopt new USB API. + * src/usb_msc.c (usb_start_transmit): Use usb_lld_write. + (EP6_IN_Callback): Use usb_lld_tx_data_len and usb_lld_write. + (usb_start_receive): Use usb_lld_rx_enable. + (EP7_OUT_Callback): Use usb_lld_rx_data_len, usb_lld_rxcpy + and usb_lld_rx_enable + (msc_handle_command): Use usb_lld_stall_rx and usb_lld_stall_tx. + + * src/usb_lld.h (usb_lld_stall_tx, usb_lld_stall_rx) + (usb_lld_tx_data_len): New. + + * src/main.c (STDOUTthread): Use usb_lld_write. + + * src/usb-icc.c (EP1_IN_Callback, icc_error, icc_power_on) + (icc_send_status, icc_send_data_block, icc_send_params): Use + usb_lld_write (was: USB_SIL_Write). + (EP2_OUT_Callback): Use usb_lld_rx_data_len, usb_lld_rxcpy, + and usb_lld_rx_enable (was: USB_SIL_Read and SetEPRxValid). + (icc_prepare_receive): Use usb_lld_rx_enable. + + * src/stmusb.mk (STMUSBSRC): Dont' include usb_sil.c. + + * src/usb_lld.h (usb_lld_txcpy, usb_lld_tx_enable) + (usb_lld_write, usb_lld_rx_enable, usb_lld_rx_data_len) + (usb_lld_rxcpy): New. + + * src/usb_prop.c (SetEPRxCount_allocated_size): Fix the + implementation. (ST's SetEPRxCount is actually meant to + setup allocated size, which is confusing). + (gnuk_device_init): Don't call USB_SIL_Init. + +2012-01-10 Niibe Yutaka + + * src/openpgp.c (GPGthread): Allow INS_RESET_RETRY_COUNTER and + INS_PUT_DATA for pinentry targets. + +2012-01-05 Niibe Yutaka + + * src/openpgp.c (cmd_select_file): Check DF name. + + * tool/pinpadtest.py: Rename from pinpad-test.py. + +2011-12-28 Niibe Yutaka + + * src/usb_prop.c (SetEPRxCount_allocated_size): New. + (gnuk_device_reset): Use SetEPRxCount_allocated_size. + * src/usb_msc.c (usb_start_receive): Don't set RxCount register + here. + * STM32_USB-FS-Device_Driver/src/usb_core.c (Standard_ClearFeature) + (Post0_Process): Don't need to set RxCount register. + + * src/usb_prop.c (msc_lun_info) [PINPAD_DND_SUPPORT]: ifdef-out. + + * src/usb-icc.c (EP2_OUT_Callback): Fix apdu size == 49 bug, + we don't assume host sends ZLP (But accepts ZLP, just in case). + +2011-12-22 Niibe Yutaka + + * src/openpgp-do.c (extended_capabilities) [CERTDO_SUPPORT]: + conditionalize. + +2011-12-21 Niibe Yutaka + + * src/openpgp-do.c (gpg_do_get_data) [CERTDO_SUPPORT]: ifdef out. + + * src/gnuk.ld.in (.gnuk_ch_certificate): Only valid + when --enable-certdo. + + * src/flash.c (flash_check_blank) [CERTDO_SUPPORT]: ifdef out. + (flash_erase_binary) [CERTDO_SUPPORT]: Likewise. + (flash_write_binary) [CERTDO_SUPPORT]: Likewise. + + * src/configure (certdo): New. + (--enable-certdo, --disable-certdo): New options. + Remove cheking for /dev/random. + + * src/config.h.in (@CERTDO_DEFINE@): New. + +2011-12-20 Niibe Yutaka + + * src/usb_msc.c (msc_handle_command): SCSI_START_STOP_UNIT command + with stop/eject/close means cancelling pinentry. + + * src/pin-dnd.c (pinpad_finish_entry, parse_directory_sector): + Implement "cancel". + (pinpad_getline): Likewise. + (msc_scsi_stop): New. + +2011-12-16 Niibe Yutaka + + * tool/gnuk_put_binary_libusb.py (gnuk_token.cmd_select_openpgp): + Fix apdu parameter. + + * tool/gnuk_put_binary.py (GnukToken.cmd_select_openpgp): Ditto. + + * tool/pinpad-test.py: New. + +2011-12-14 Niibe Yutaka + + * Version 0.16. + + * src/usb_desc.c (gnukStringSerial): Updated. + + * boards/STM8S_DISCOVERY/board.h, board.c: Fix for PINPAD_SUPPORT. + * boards/STBEE_MINI/board.h, board.c: Likewise. + * boards/STBEE/board.h, board.c: Likewise. + * boards/FST_01/board.c: Likewise. + +2011-12-13 Niibe Yutaka + + Add pinpad DND support. + * src/Makefile.in (CSRC) [ENABLE_PINPAD]: Add usb_msc.c. + * src/configure (pinpad): Add dnd support. + * src/gnuk.h [PINPAD_DND_SUPPORT]: Add declarations. + * src/main.c (STDOUTthread): Add PUSH packet. + (main) [PINPAD_DND_SUPPORT]: Call msc_init. + * src/usb_conf.h (EP_NUM): Add the case of PINPAD_DND_SUPPORT. + (ENDP6_TXADDR, ENDP7_RXADDR): New. + (ENDP4_TXADDR, ENDP5_RXADDR): Changed for smaller buffer. + * src/usb_desc.c (gnukConfigDescriptor): Add Mass storage device. + * src/usb_msc.c, src/usb_msc.h, src/pin-dnd.c: New. + * src/usb_prop.c: Include "usb_msc.h". + (gnuk_device_reset): Add initialization of ENDP6 and ENDP7. + (gnuk_device_SetInterface): Add initialization of ENDP6 and ENDP7. + (NUM_INTERFACES): Handle cases for PINPAD_DND_SUPPORT. + (msc_lun_info): New. + (gnuk_setup_with_data, gnuk_setup_with_nodata): Handle standard + request for Mass storage device. + * Virtual_COM_Port/usb_desc.h (VIRTUAL_COM_PORT_DATA_SIZE): Since + there isn't enough hardware buffer, smaller value (was: 64). + + * src/ac.c (verify_user_0): Add access argument. + (verify_pso_cds, verify_other, verify_admin_0): Follow the change. + * src/openpgp.c (cmd_change_password): Likewise. + +2011-12-08 Niibe Yutaka + + * src/usb-icc.c: Not include "usb_desc.h". + + * src/usb_endp.c (EP5_OUT_Callback): Fix minor bug. + +2011-12-07 Niibe Yutaka + + * src/usb_desc.c (gnukDeviceDescriptor): Changed bcdUSB = 1.1. + Gnuk device conforms to USB 2.0 full speed device, but when it was + 2.0, some OS informs users, "you can connect the device to 2.0 + compliant hub so that it can have better bandwidth", which is not + the case for full speed device. + + * src/openpgp.c (GPGthread): Handle bConfirmPIN parameter. + + * src/usb-icc.c (icc_handle_data): Pass PC_to_RDR_Secure + information to gpg_thread using memory of cmd_APDU. + +2011-12-01 Niibe Yutaka + + * src/gnuk.h (EV_PINPAD_INPUT_DONE, EV_NOP, EV_CMD_AVAILABLE) + (EV_VERIFY_CMD_AVAILABLE, EV_MODIFY_CMD_AVAILABLE): New. + * src/usb-icc.c (icc_power_off, icc_handle_data): Use EV_NOP, + EV_CMD_AVAILABLE, EV_VERIFY_CMD_AVAILABLE, and EV_MODIFY_CMD_AVAILABLE. + * src/pin-cir.c (cir_timer_interrupt): Use EV_PINPAD_INPUT_DONE. + * src/pin-dial.c (dial_sw_interrupt, pinpad_getline): Ditto. + (EV_SW_PUSH): Remove. + + * src/openpgp.h (GPG_FUNCTION_NOT_SUPPORTED): New. + (GPG_CONDITION_NOT_SATISFIED): New. + * src/openpgp.c (cmd_change_password): Use GPG_FUNCTION_NOT_SUPPORTED. + + * src/openpgp.c (cmd_verify, cmd_change_password) + (cmd_reset_user_password, cmd_put_data): Remove pinpad handling... + (GPGthread): ... and implement pinpad handling here. + +2011-11-29 Niibe Yutaka + + * src/openpgp.c (cmd_put_data) [PINPAD_SUPPORT]: Support pinpad + input (for reset code). + +2011-11-24 Niibe Yutaka + + * Version 0.15. + * src/usb_desc.c (gnukStringSerial): Updated. + +2011-11-22 Niibe Yutaka + + * tool/dfuse.py (DFU_STM32.download, DFU_STM32.verify): Support + unaligned write and hole. + +2011-11-14 Niibe Yutaka + + * boards/FST_01/{mcuconf.h,board.h,board.c}: New. + +2011-11-01 Niibe Yutaka + + * src/pin-dial.c (pinpad_getline): New. + (pin_main): Remove. + + * boards/STBEE_MINI/board.h (TIMx): Define. + boards/STBEE/board.h (TIMx): Ditto. + boards/STM8S_DISCOVERY/board.h: Ditto. + + * src/pin-cir.c (pinpad_getline): New. + (cir_timer_interrupt, cir_ext_interrupt): Use TIMx. + (cir_key_is_backspace, cir_key_is_enter, pin_main, pindisp): + Remove. + (cir_codetable_dell_mr425, cir_codetable_aquos) + (cir_codetable_regza, cir_codetable_bravia, ch_is_backspace) + (ch_is_enter, find_char_codetable, hex, cir_getchar): New. + (cir_timer_interrupt): Don't filter out ADDRESS. + + * src/openpgp.c (get_pinpad_input): Don't invoke thread, + but just call pinpad_getline. + + * src/main.c (display_interaction, display_fatal_code) + (display_status_code, led_blink): New. + (main): Call display_* routine. + (fatal): Notify main thread. + * src/usb_prop.c (gnuk_device_SetConfiguration): Notify main + thread. + + * src/pin-cir.c (pindisp): Remove. + + * boards/FST_01_00: New (for 8MHz FST-01). + + * src/ac.c (calc_md): Fix comparison. + + * src/call-rsa.c (RSA_SIGNATURE_LENGTH): Use KEY_CONTENT_LEN. + (rsa_sign, rsa_decrypt): Likewise. + (modulus_calc): Don't assume it's 2048-bit. + + * src/ac.c (verify_user_0): Fix for non-initialized PW1. + + * src/Makefile.in (MCFLAGS): Override MCFLAGS option for newer + GCC of summon-arm-toolchain to add -mfix-cortex-m3-ldrd. + NOTE: This should not be needed (as -mcpu=cortex-m3 defaults + to -mfix-cortex-m3-ldrd for GCC-proper), but it is needed + to select arm-none-eabi/lib/thumb2/libc.a correctly. + +2011-10-14 NIIBE Yutaka + + * src/gnuk.ld.in (__main_stack_size__): It's 1KB (was 512 byte). + 2011-10-07 NIIBE Yutaka * Version 0.14. diff --git a/GNUK_USB_DEVICE_ID b/GNUK_USB_DEVICE_ID new file mode 100644 index 0000000..65a3b25 --- /dev/null +++ b/GNUK_USB_DEVICE_ID @@ -0,0 +1,3 @@ +# VID:PID bcdDev Product_STRING Vender_STRING +234b:0000 0200 Gnuk Token Free Software Initiative of Japan +########## ## ########## ################# diff --git a/NEWS b/NEWS index 8644738..94dddc2 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,240 @@ Gnuk NEWS - User visible changes +* Major changes in Gnuk 1.0.2 + + Released 2012-12-??, by NIIBE Yutaka + +** Product string is now "Gnuk Token" (was: "FSIJ USB Token") +Since the USB ID Repository suggests not including vendor name +in product string, we changed the product string. + +** New tool (experimental): test/upgrade_by_passwd.py +This is the tool to install new firmware to Gnuk Token, provided +that it's just shipped from factory (and nothing changed). It +authenticate as admin by factory setting, register a public key +for firmware upgrade, and then, does firmware upgrade. + +** tool/gnuk_upgrade.py supports '-k' option +It now supports RSA key on the host PC (not the one on the Token). + +** New tool: tool/get_raw_public_key.py +This is a script to dump raw data of RSA public key, which is useful +to register to Gnuk Token as a firmware upgrade key. + +** New tool: tool/gnuk_remove_keys_libusb.py +This tool is libusb version of gnuk_remove_keys.py. Besides, a bug in +gnuk_remove_keys.py was fixed. + +** CCID protocol fix +When time extension is requested by Gnuk Token to host PC, argument +field was 0, which was wrong (but it works for most PC/SC +implementations and GnuPG internal driver). Now it's 1, which means +1*BWT. + + +* Major changes in Gnuk 1.0.1 + + Released 2012-08-03, by NIIBE Yutaka + +** USB SerialNumber String +In 1.0, it has a bug for USB SerialNumber String. It has been fixed +in 1.0.1. + + +* Major changes in Gnuk 1.0 + + Released 2012-07-21, by NIIBE Yutaka + +This is bug fixes only release. + + +* Major changes in Gnuk 0.21 + + Released 2012-07-06, by NIIBE Yutaka + +** Test suite +A functinality test suite is added under test/ directory. + +** New tool: stlinkv2.py +This tool is SWD flash ROM writer with ST-Link/V2. + +** New tool: usb_strings.py +This tool is to dump USB strings, which include revision detail and config +options. + +** Protection improvement (even when internal data is disclosed) +Even if PW1 and PW3 is same, content of encrypted DEK is different +now. + + +* Major changes in Gnuk 0.20 + + Released 2012-06-19, by NIIBE Yutaka + +** Key generation feature added +Finally, key generation is supported. Note that it may be very slow. +It may take a few minutes (or more) to generate two or three keys, +when you are unlucky. + +** DnD pinentry support is deprecated +Once, DnD pinentry was considered a great feature, but it found that +it is difficult to remember moves of folders. + +** gnuk_upgrade.py assumes using another token for authentication +Use of another token for authentication is assumed now. This is +incompatible change. Note that when you upgrade a token of version +0.19 to 0.20 (or later), you need gnuk_upgrade.py of version 0.19. + +** KDF (Key Derivation Function) is now SHA-256 +Keystring is now computed by SHA-256 (it was SHA1 before). + +** Protection improvements (even when internal data is disclosed) +Three improvements. (1) Even if PW1 and Reset-code is same, content +of encrypted DEK is different now. (2) DEK is now encrypted and +decrypted by keystring in ECB mode (it was just a kind of xor by +single block CFB mode). (3) Key data plus checksum are encrypted in +CFB mode with initial vector (it will be able to switch OCB mode +easily). + +** LED display output change +LED display output by Gnuk is now more reactive. It shows status code +when it gets GET_STATUS message of CCID. When you communicate Gnuk by +internal CCID driver of GnuPG (instead of PC/SC), and enable +'debug-disable-ticker' option in .gnupg/scdaemon.conf, it is more +silent now. + + +* Major changes in Gnuk 0.19 + + Released 2012-06-06, by NIIBE Yutaka + +** Firmware upgrade feature +Firmware upgrade is now possible after the public key authentication +using EXTERNAL AUTHENTICATE command of ISO 7816. Firmware upgrade is +done together with reGNUal, the firmware upgrade program. + +** System service blocks at the beginning of flash ROM. +Once flash ROM is protected, first 4-KiB cannot be modified. Gnuk +use this area for "system service". Note that this area will not +be able to be modified by firmware upgrade (or by any method). + +** New tool: gnuk_upgrade.py +The tool gnuk_upgrade.py is to do public key authentication using +gpg-agent and send reGNUal to Gnuk. Then, we put new Gnuk binary +into the device with reGNUal. + +** USB strings for revision detail, configure options, and system service. +USB strings now have more information. There are revision detail +string, configure options string, system service version string, as +well as vendor string and product string. These strings could be +examined to check Gnuk Token. + + +* Major changes in Gnuk 0.18 + + Released 2012-05-15, by NIIBE Yutaka + +** New mandatory option '--vidpid' for configure +You must specify USB vendor ID and product ID for Gnuk. +The file GNUK_USB_DEVICE_ID lists valid USB device IDs. + +** New tool: gnuk_remove_keys.py +The tool gnuk_remove_keys.py is to remove all keys in Gnuk Token +and reset PW1 and RC (if any). + +** New USB stack +Gnuk used to use USB stack of USB-FS-Device_Lib by ST. Now, it has +original implementation. Hopefully, size and quality are improved. + + +* Major changes in Gnuk 0.17 + + Released 2012-02-02, by NIIBE Yutaka + +** USB CCID/ICCD protocol implementation change +Gnuk now only supports short APDU level exchange, not supporting +extended APDU level exchange. Thus, Gnuk could be compatible to older +host side software implementation. + +** ISO 7816 SELECT command behavior is somewhat strict now +Old implementations do not check DF name for SELECT command. +This causes some trouble when Gnuk Token is identified as if it were +different card/token. Now, DF name of OpenPGP card is checked. + +** USB CCID/ICCD low-level bug is fixed +When the size of command APDU data is just 49, the lower level packet +size is 64. This is maximum size of BULK-OUT transfer packet, and +caused trouble in the past implementations. Example is setting url +(0x5f50) as: http://www.gniibe.org/adpu-string-size-is-just-49 +This is because the past implementations expect ZLP (zero length +packet). Now, it has been fixed. You can use any size of string. + +** CERT.3 Data Object (0x7f21) is now optional +As there's no valid use case for this data object and it does not +work as current version of GnuPG, this is now optional feature. +You can enable this data object by specifying --enable-certdo at +configure time. + +** With DnD pinentry, user can cancel pin input +Now, user can cancel pin input by unmounting device before finishing +DnD. + +** New tool: pinpadtest.py +The tool pinpadtest.py is PC/SC test tool for pinentry of pinpad with +OpenPGP card v2. + + +* Major changes in Gnuk 0.16 + + Released 2011-12-14, by NIIBE Yutaka + +** DnD pinentry support is added and it's default to pinentry support +DnD pinentry support doesn't require any hardware extension, but +emulates mass storage class device of USB. User inputs pass phrase +by "drag and drop"-ing folders using file manager or something. + +** Bug fix for VERIFY for CHV2 +With no keys, VERIFY command for CHV2 used to fail even if pass phrase +is correct. It was intentional, because CHV2 verification would be +useless with no keys. But there is a corner case for PRIVATE-DOs, +which may requires CHV2 verification. Even though Gnuk doesn't +support any PRIVATE-DOs, it is good to be fixed. + +** Changed bcdUSB = 1.1 +Gnuk device conforms to USB 2.0 full speed device, but when it was +2.0, some OS informs users, "you can connect the device to 2.0 +compliant hub so that it can have better bandwidth", which is not +the case for full speed device. + + +* Major changes in Gnuk 0.15 + + Released 2011-11-24, by NIIBE Yutaka + +** New targets: FST_01 and FST_01_00 +Flying Stone Technology's open hardware, Flying Stone Tiny 01 is +supported. + +** Flash writing tool for "DfuSe" is improved +Now, it supports holes and unaligned blocks in hex file. + +** Experimental PIN-pad support (by TV controller) change +Now, Gnuk has codetables for conversion from CIR code to ASCII code. +Note that only four controllers (of Dell, Sharp, Sony, and Toshiba) +are supported and tested. + +** It is possible for users to keep using OPENPGP_CARD_INITIAL_PW1 +With a bug fix of verify_user_0, it's now possible. Although it's not +recommended. + +** Important bug fix and a workaround +In version 0.14, __main_stack_size__ (for interrupt handler) was too +small for some cases. This is fixed in 0.15. + +In src/Makefile.in, added -mfix-cortex-m3-ldrd for correctly linking C +library for thumb2. This is needed for newer summon-arm-toolchain. + + * Major changes in Gnuk 0.14 Released 2011-10-07, by NIIBE Yutaka diff --git a/README b/README index a974551..256ea99 100644 --- a/README +++ b/README @@ -1,26 +1,26 @@ -Gnuk - software for GnuPG USB Token +Gnuk - An Implementation of USB Cryptographic Token for GnuPG - Version 0.14 - 2011-10-07 - Niibe Yutaka + Version 1.0.1 + 2012-08-03 + Niibe Yutaka Free Software Initiative of Japan What's Gnuk? ============ -Gnuk is software implementation of a USB token for GNU Privacy Guard. -Gnuk supports OpenPGP card protocol version 2, and it runs on STM32 -processor. +Gnuk is an implementation of USB cryptographic token for GNU Privacy +Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on +STM32F103 processor. I wish that Gnuk will be a developer's soother who uses GnuPG. I have been nervous of storing secret key(s) on usual secondary storage. -While I want to work at different places, but it is not the choice for -me to bring a card reader all the time. With Gnuk, this issue will be -solved by a USB token which is small enough. +There is a solution with OpenPGP card, but it is not the choice for +me, as card reader is not common device. With Gnuk, this issue will +be solved by a USB token. Please look at the graphics of "gnuk.svg" for the software name. My -son used to be with his NUK(R), always, everywhere. I am with a USB -Token by "Gnuk", always, everywhere. +son used to be with his NUK(R), always, everywhere. Now, I am with a +USB Cryptographic Token by "Gnuk", always, everywhere. FAQ @@ -30,18 +30,15 @@ Q0: How Gnuk USB Token is superior than other solutions (OpenPGP card 2.0, GPF Crypto Stick, etc.) ? http://www.g10code.de/p-card.html http://www.privacyfoundation.de/crypto_stick/ -A0: IMRHO, not quite. There is no ready-to-use out-of-box product. - (It is welcome for me that some vendor will manufacture Gnuk USB - Token. Even I can help design of hardware, if needed.) - Good points are: +A0: Good points of Gnuk are: * If you have skill of electronics and like DIY, you can build Gnuk Token cheaper (see Q8-A8). * You can study Gnuk to modify and to enhance. For example, you can implement your own authentication method with some sensor - such as acceleration sensor. + such as an acceleration sensor. * It is "of Free Software"; Gnuk is distributed under GPLv3+, - "by Free Software"; Gnuk development requires only Free Software - (GNU Toolchain, Python, etc.), + "by Free Software"; Gnuk development requires only Free Software + (GNU Toolchain, Python, etc.), "for Free Software"; Gnuk supports GnuPG. Q1: What kind of key algorithm is supported? @@ -54,24 +51,25 @@ Q3: What's your recommendation for target board? A3: Orthodox choice is Olimex STM32-H103. If you have skill of electronics and like DIY, STM32 part of STM8S Discovery Kit might be the best choice. - Currently FST-01 (Flying Stone Tiny 01) is under development, - it will be the best choice, hopefully. + FST-01 (Flying Stone Tiny 01) will be soon available for sale, + and it will be the best choice, hopefully. Q4: What's version of GnuPG are you using? A4: In Debian GNU/Linux system, I use gnupg 1.4.11-3 and gnupg-agent - 2.0.14-2 (in sid). With older versions, you can only sign with SHA1. + 2.0.18-2. With older versions, you can only sign with SHA1. See: http://www.fsij.org/gnuk/gnupg2-fixes-needed Q5: What's version of pcscd and libccid are you using? A5: In Debian GNU/Linux system, I use pcscd 1.5.5-4 and libccid 1.3.11-2, which is in squeeze. Note that you need to edit /etc/libccid_Info.plist when using libccid (< 1.4.1). + Note that pcscd and libccid are optional, you can use Gnuk without them. Q6: What kinds of hardware is required for development? -A6: You need a target board plus a JTAG debugger. If you just want to - test Gnuk for target boards with DfuSe, JTAG debugger is not - the requirement. Note that for real use, you need JTAG debugger - to enable flash ROM protection. +A6: You need a target board plus a JTAG/SWD debugger. If you just + want to test Gnuk for target boards with DfuSe, JTAG debugger is + not the requirement. Note that for real use, you need JTAG/SWD + debugger to enable flash ROM protection. Q7: How much does it cost? A7: Olimex STM32-H103 plus ARM-USB-TINY-H cost 70 Euro or so. @@ -82,20 +80,46 @@ A8: STM8S Discovery Kit costs 750 JPY (< $10 USD) only. You can build http://www.fsij.org/gnuk/jtag_dongle_ftdi2232 Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up? + A9: GnuPG's SCDaemon has problems for handling insertion/removal of - card/reader (problems are fixed in trunk). When your newly - inserted token is not found by GnuPG, try killing scdaemon and let - it to be invoked again. I do: - $ killall -9 scdaemon + card/reader (problems are fixed in trunk, and backported to 2.0 + branch, it will be 2.0.20). When your newly inserted token is not + found by GnuPG, try killing scdaemon and let it to be invoked + again. I do: + + $ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye + and confirm scdaemon doesn't exist, then, - $ gpg-connect-agent learn /bye + + $ gpg-connect-agent learn /bye + +Qa: With GNOME 2, I can't use Gnuk Token for SSH. How can we use it for SSH? +Aa: You need to deactivate seahorse-agent and gnome-keyring, but use + gpg-agant for the role of ssh-agent. For gnome-keyring please do: + + $ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false + +Qb: With GNOME 3, I can't use Gnuk Token at all. Why? +Ab: That's because gnome-keyring-daemon interferes GnuPG. Type: + + $ gnome-session-properties + + and at the tab of "Startup Programs", disable check buttons for + "GPG Password Agent" and "SSH Key Agent". + +Qc: Do you know a good SWD debugger to connect FST-01 or something? +Ac: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM + writer program. Release notes ============= -This is fifteenth release of Gnuk. While it works well for specific -usages and it is considered stable, it is still somewhat experimental. +This is a minor release in version 1.0 series of Gnuk. + +While it is daily use for more than a year, some newly introduced +features (including key generation and firmware upgrade) should be +considered experimental. Tested features are: @@ -112,35 +136,42 @@ Tested features are: * Changing value of password status bytes (0x00C4): forcesig * Verify with pin pad * Modify with pin pad + * Card holder certificate (read) + * Removal of keys + (Overriding key import is not supported, + but you can remove all keys to import again). + * Key generation on device side + +Original features of Gnuk, tested lightly: + + * OpenPGP card serial number setup + * Card holder certificate (write by UPDATE BINARY) + * Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal It is known not-working well: * For some version of kernel and libccid, --enable-debug can't - work well. Please disable DEBUG option if it doesn't work well. + work well. Please make sure to disable DEBUG option if it + doesn't work well. - * Card holder certificate - It is implemented in Gnuk side. But its size matters (> - 1KB). GnuPG cannot handle a data object of large size with - PC/SC backend. Specifically, handle_transmit function in - pcsc-wrapper.c uses the buffer of size 1024-byte. - -Not supported feature(s): - - * Overriding key import. You need to remove all keys first. - * Key generation on device side +It is known that the combination of libccid 1.4.1 (or newer) with +libusb 1.0.8 (or older) has a minor problem. It is rare but it is +possible for USB communication to be failed, because of a bug in +libusb implementation. Use libusbx 1.0.9 or newer, or don't use +PC/SC, but use internal CCID driver of GnuPG. Targets ======= -We use Olimex STM32-H103 board. We also use STM32 part of STM8S -Discovery Kit. +We use Olimex STM32-H103 board and Flying Stone Tiny 01 (FST-01). We +also use STM32 part of STM8S Discovery Kit. With DfuSe support, CQ STARM, STBee, and STBee Mini are also our targets. But those targets with DfuSe are basically not for normal use but for experiments, because it would be impossible for DfuSe to disable read from flash. For real use, please consider killing DfuSe -and enable read protection using JTAG debugger. +and enabling read protection using JTAG debugger. I think that it could run on Olimex STM32-P103, or other boards with STM32F103. Besides, we are porting it to STM32 Primer 2. @@ -157,12 +188,22 @@ Another PIN-pad support is connecting rotary encoder, push switch and 7-segment LED display. Both of PIN verification and PIN modification are supported for this circuit extension. +Note that you need pinpad support for GnuPG to use PIN-pad enabled +Gnuk. The pinpad support for GnuPG is currently in the master branch +of GnuPG git repository at git.gnupg.org, and it's under evaluation. +When it will be considered stable, it will be put onto stable branch. + Souce code ========== Gnuk source code is under src/ directory. +Note that SHA-2 hash function implementation, src/sha256.c, is based +on the original implementation by Dr. Brian Gladman. See: + + http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php + License ======= @@ -171,12 +212,12 @@ It is distributed under GNU General Public Licence version 3 or later (GPLv3+). Please see src/COPYING. Please note that it is distributed with external source code too. -Please read relevant licenses for external source code, too. +Please read relevant licenses for external source code as well. The author(s) of Gnuk expect users of Gnuk will be able to access the source code of Gnuk, so that users can study the code and can modify if needed. This doesn't mean person who has a USB Token by Gnuk -should be able to acess everything on the Token, regardless of its +should be able to access everything on the Token, regardless of its protections. Private keys, and other information should be protected properly. @@ -195,28 +236,73 @@ Gnuk is distributed with external source code. * polarssl-0.14.0/ -- PolarSSL 0.14.0 Taken from http://polarssl.org/ - We use PolarSSL for RSA computation, AES encryption/decryption - and SHA-1 computation. + We use PolarSSL for RSA computation, AES encryption/decryption. The file include/polarssl/bn_mul.h is heavily modified for ARM Cortex-M3. -* STM32_USB-FS-Device_Driver/ -- a part of USB-FS-Device_Lib -* Virtual_COM_Port/ -- a part of USB-FS-Device_Lib + The files include/polarssl/rsa.h, library/rsa.c, + include/polarssl/bignum.h, and library/bignum.c are modified so that + f_rng function returns unsigned char. - STM32F10x USB Full Speed Device Library (USB-FS-Device_Lib) - is a STM32F10x library for USB functionality. + The file library/rsa.c is modified so that it only computes things + needed for Gnuk. - I took Libraries/STM32_USB-FS-Device_Driver and - Project/Virtual_COM_Port in STM32_USB-FS-Device_Lib distribution. - See http://www.st.com/ for detail. + The file library/aes.c is modified so that some constants can + go to .sys section. + + +USB vendor ID and product ID (USB device ID) +============================================ + +When you have a vender ID and assign a product ID for Gnuk, edit the +file GNUK_USB_DEVICE_ID and add an entry for yours. In this case, +please contact Niibe, so that it is listed to the file in the official +release of the source code. + +When you are modifing Gnuk and installing the binary to device, you +should replace the vendor string to yours, so that users can see it's +not by original vendor, and it is modified version. + +FSIJ allows you to use USB device ID of FSIJ (234b:0000) for devices +with Gnuk under one of following conditions: + + * For everyone for experimental purpose: + + - You must not distribute a binary with FSIJ's USB device ID, but + must use the binary by yourself only for your experiment. Note + that "Distributing binary" includes distributing a device which + holds the binary. + + * For general individuals: + + - You must use your Gnuk device with a card serial number which is + *not* by FSIJ. Easy one would be a card serial number generated + by chip unique ID. + + * For individuals with explicit permission from FSIJ. + + - You should have an assigned card serial number by FSIJ, + please use that number for your device. + (There a file 'GNUK_SERIAL_NUMBER' in the official release.) + +FSIJ could give companies or business entities "second source +manufacturer" license to use USB device ID of FSIJ for devices with +unmodified version of Gnuk, provided they support Free Software and +respect users' freedom for computing. Please ask FSIJ for the +license. + +Otherwise, companies which want to distribute Gnuk devices, please use +your own USB vendor ID and product ID. Please replace vendor string +and possibly product string to yours, when you modify Gnuk. Host Requirements ================= -For GNU/Linux, libccid version >= 1.3.11 is required. -libccid version == 1.3.9 is known not working well by the issue [r4235]. +For GNU/Linux, PC/SC service is an option, you can use GnuPG's +internal CCID driver instead. If you chose using PC/SC service, +libccid version >= 1.3.11 is recommended for GNU/Linux. I think that it should not be requirment but the kernel version of my use is: Linux version 2.6.32-5-686 (Debian 2.6.32-18) (ben@decadent.org.uk) (gcc version 4.3.5 (Debian 4.3.5-2) ) #1 SMP Sat Jul 24 02:27:10 UTC 2010 @@ -230,8 +316,31 @@ How to compile You need GNU toolchain and newlib for 'arm-none-eabi' target. -See http://github.com/uwehermann/summon-arm-toolchain/ for preparation -of GNU Toolchain for 'arm-none-eabi' target. +See http://github.com/esden/summon-arm-toolchain/ (which includes fix +of binutils-2.21.1) for preparation of GNU Toolchain for +'arm-none-eabi' target. This is for GCC 4.5. + +# Note that we need to link correct C library (for string functions). +# For this purpose, Makefile.in contains following line: +# +# MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd +# +# This should not be needed (as -mcpu=cortex-m3 means +# -mfix-cortex-m3-ldrd), but in practice it is needed for +# the configuration of patch-gcc-config-arm-t-arm-elf.diff in +# summon-arm-toolchain. +# +# In ChibiOS_2.0.8/os/ports/GCC/ARM/rules.mk, it specifies +# -mno-thumb-interwork option. This means that you should not +# link C library which contains ARM (not Thumb) code. + +Recently, there is "gcc-arm-embedded" project. See: + + https://launchpad.net/gcc-arm-embedded/ + +It is based on GCC 4.6. For version 4.6-2012-q2-update, you'd +need "-O3 -Os" instead of "-O2" and it will be slightly better. + Change directory to `src': @@ -239,7 +348,11 @@ Change directory to `src': Then, run `configure': - $ ./configure + $ ./configure --vidpid= + +Here, you need to specify USB vendor ID and product ID. For FSIJ's, +it's: --vidpid=234b:0000 . Please read section 'USB vendor ID and +product ID' above. Type: @@ -268,6 +381,36 @@ Then, with another terminal, type following to write "gnuk.elf" to Flash ROM: $ +Flying Stone Tiny 01 +-------------------- + +If you are using Flying Stone Tiny 01, you need a SWD writer. I am +using revision 946 of Simon Qian's Versaloon. + + svn checkout -r 946 http://vsprog.googlecode.com/svn/trunk/ + +For OpenOCD, we need unofficial patch. + +See the article of Versaloon Forum: + + http://www.versaloon.com/bbs/viewtopic.php?p=16179 + + +Type following to invoke OpenOCD: + + $ openocd -f interface/vsllink.cfg -c "transport select swd" -c "swd_mode 2" -f target/stm32f1x.cfg + +Then, with another terminal, type following to write "gnuk.elf" to Flash ROM: + + $ telnet localhost 4444 + > reset halt + > flash write_image erase gnuk.elf + > reset + > exit + $ + + + STM8S Discovery Kit ------------------- @@ -345,7 +488,7 @@ PyUSB (python-usb package in Debian). If scdaemon is running, please kill it, or you will get "Smartcard Exception" by "Sharing violation". - $ killall -9 scdaemon + $ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye In case of PyUSB tool, you need to stop pcscd. @@ -424,11 +567,15 @@ This entry has been added into libccid 1.4.1 already ([r5425]). Testing Gnuk ------------ -Try following to see Gnuk runs: +Type following command to see Gnuk runs: $ gpg --card-status +Besides, there is a functinality test under test/ directory. See +test/README. + + Personalize the Token and import keys ------------------------------------- @@ -441,18 +588,21 @@ command is: Note that the factory setting of user password is "123456" and admin password is "12345678" as the specification. -No, Gnuk doesn't support key generation. You need to create your -keys on your computer, and import them to Gnuk Token. After you create -your keys (they must be 2048-bit RSA), you can import them. +It is recommended to create your keys on your computer, and import +them to Gnuk Token. After you create your keys (they must be 2048-bit +RSA), you can import them. -For detail, please see doc/DEMO and doc/DEMO-2. +Gnuk supports key generation, but this feature is young and should be +considered experimental. + +For detail, please see doc/note/DEMO and doc/note/DEMO-2. Note that it make sense to preserve your keys on your computer so that you can import the keys (again) to (possibly another) Gnuk Token. In this case, you can use GnuPG's option to specify the home directory by --homedir. -After creating keys by: +After creating keys on your computer by: $ gpg --gen-key ... @@ -504,6 +654,12 @@ You can observe the traffic of USB using "usbmon". See the file: linux/Documentation/usb/usbmon.txt +Firmware update +=============== + +See doc/note/firmware-update. + + Read-only Git Repository ======================== diff --git a/STM32_USB-FS-Device_Driver/inc/otgd_fs_cal.h b/STM32_USB-FS-Device_Driver/inc/otgd_fs_cal.h deleted file mode 100644 index 17761d4..0000000 --- a/STM32_USB-FS-Device_Driver/inc/otgd_fs_cal.h +++ /dev/null @@ -1,258 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_cal.h -* Author : STMicroelectronics -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Header of OTG FS Device Core Access Layer interface. -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ -#ifndef __OTG_CORE_H__ -#define __OTG_CORE_H__ - -#ifdef STM32F10X_CL - -#include "stm32f10x.h" -#include "usb_type.h" - -#if defined ( __CC_ARM ) - #define __packed __packed /*!< packing keyword for ARM Compiler */ -#elif defined ( __ICCARM__ ) - #define __packed __packed /*!< packing keyword for IAR Compiler */ -#elif defined ( __GNUC__ ) - #define __packed __attribute__ ((__packed__)) /*!< packing keyword for GNU Compiler */ -#elif defined ( __TASKING__ ) /*!< packing keyword for TASKING Compiler */ - #define __packed -#endif /* __CC_ARM */ - -/******************************************************************************* - define and types -*******************************************************************************/ - -#define DEVICE_MODE_ENABLED - -#ifndef NULL -#define NULL ((void *)0) -#endif - - -#define DEV_EP_TX_DIS 0x0000 -#define DEV_EP_TX_STALL 0x0010 -#define DEV_EP_TX_NAK 0x0020 -#define DEV_EP_TX_VALID 0x0030 - -#define DEV_EP_RX_DIS 0x0000 -#define DEV_EP_RX_STALL 0x1000 -#define DEV_EP_RX_NAK 0x2000 -#define DEV_EP_RX_VALID 0x3000 - -/***************** GLOBAL DEFINES ***************************/ - -#define GAHBCFG_TXFEMPTYLVL_EMPTY 1 -#define GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 - -#define GAHBCFG_GLBINT_ENABLE 1 -#define GAHBCFG_INT_DMA_BURST_SINGLE 0 -#define GAHBCFG_INT_DMA_BURST_INCR 1 -#define GAHBCFG_INT_DMA_BURST_INCR4 3 -#define GAHBCFG_INT_DMA_BURST_INCR8 5 -#define GAHBCFG_INT_DMA_BURST_INCR16 7 -#define GAHBCFG_DMAENABLE 1 -#define GAHBCFG_TXFEMPTYLVL_EMPTY 1 -#define GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 - -#define GRXSTS_PKTSTS_IN 2 -#define GRXSTS_PKTSTS_IN_XFER_COMP 3 -#define GRXSTS_PKTSTS_DATA_TOGGLE_ERR 5 -#define GRXSTS_PKTSTS_CH_HALTED 7 - -#define DEVICE_MODE 0 -#define HOST_MODE 1 - -/***************** DEVICE DEFINES ***************************/ - -#define DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 -#define DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 -#define DSTS_ENUMSPD_LS_PHY_6MHZ 2 -#define DSTS_ENUMSPD_FS_PHY_48MHZ 3 - -#define DCFG_FRAME_INTERVAL_80 0 -#define DCFG_FRAME_INTERVAL_85 1 -#define DCFG_FRAME_INTERVAL_90 2 -#define DCFG_FRAME_INTERVAL_95 3 - -#define DEP0CTL_MPS_64 0 -#define DEP0CTL_MPS_32 1 -#define DEP0CTL_MPS_16 2 -#define DEP0CTL_MPS_8 3 - -#define EP_SPEED_LOW 0 -#define EP_SPEED_FULL 1 -#define EP_SPEED_HIGH 2 - -#define EP_TYPE_CTRL 0 -#define EP_TYPE_ISOC 1 -#define EP_TYPE_BULK 2 -#define EP_TYPE_INTR 3 - -#define STS_GOUT_NAK 1 -#define STS_DATA_UPDT 2 -#define STS_XFER_COMP 3 -#define STS_SETUP_COMP 4 -#define STS_SETUP_UPDT 6 - - - - -typedef enum { - - USB_OTG_OK, - USB_OTG_FAIL - -}USB_OTG_Status; - -typedef struct USB_OTG_hc -{ - uint8_t hc_num; - uint8_t dev_addr ; - uint8_t ep_num; - uint8_t ep_is_in; - uint8_t speed; - uint8_t ep_type; - uint16_t max_packet; - uint8_t data_pid; - uint16_t multi_count; - uint8_t *xfer_buff; - uint32_t xfer_len; -} -USB_OTG_HC , *PUSB_OTG_HC; - -typedef struct USB_OTG_ep -{ - uint8_t num; - uint8_t is_in; - uint32_t tx_fifo_num; - uint32_t type; - uint8_t data_pid_start; - uint8_t even_odd_frame; - uint32_t maxpacket; - uint8_t *xfer_buff; - uint32_t xfer_len; - uint32_t xfer_count; -} - -USB_OTG_EP , *PUSB_OTG_EP; - -/******************************************************************************** - MACRO'S -********************************************************************************/ - -#define CLEAR_IN_EP_INTR(epnum,intr) \ - diepint.d32=0; \ - diepint.b.intr = 1; \ - WRITE_REG32(&core_regs.inep_regs[epnum]->dev_in_ep_int,diepint.d32); - -#define CLEAR_OUT_EP_INTR(epnum,intr) \ - doepint.d32=0; \ - doepint.b.intr = 1; \ - WRITE_REG32(&core_regs.outep_regs[epnum]->dev_out_ep_int,doepint.d32); - - -#define READ_REG32(reg) (*(__IO uint32_t *)reg) - -#define WRITE_REG32(reg,value) (*(__IO uint32_t *)reg = value) - -#define MODIFY_REG32(reg,clear_mask,set_mask) \ - WRITE_REG32(reg, (((READ_REG32(reg)) & ~clear_mask) | set_mask ) ) - - -#define uDELAY(usec) udelay(usec) -#define mDELAY(msec) uDELAY(msec * 1000) - -#define _OTGD_FS_GATE_PHYCLK *(__IO uint32_t*)(0x50000E00) = 0x03 -#define _OTGD_FS_UNGATE_PHYCLK *(__IO uint32_t*)(0x50000E00) = 0x00 - -/******************************************************************************* - this can be changed for real time base -*******************************************************************************/ -static void udelay (const uint32_t usec) -{ - uint32_t count = 0; - const uint32_t utime = usec * 10; - do - { - if ( ++count > utime ) - { - return ; - } - } - while (1); -} -/******************************************************************************** - EXPORTED FUNCTIONS FROM THE OTGD_FS_CAL LAYER -********************************************************************************/ -USB_OTG_Status OTGD_FS_CoreInit(void); -USB_OTG_Status OTGD_FS_SetAddress(uint32_t BaseAddress); -USB_OTG_Status OTGD_FS_EnableGlobalInt(void); -USB_OTG_Status OTGD_FS_DisableGlobalInt(void); - -USB_OTG_Status USB_OTG_CoreInitHost(void); -USB_OTG_Status USB_OTG_EnableHostInt(void); -USB_OTG_Status USB_OTG_DisableHostInt(void); - -void* OTGD_FS_ReadPacket(uint8_t *dest, uint16_t bytes); -USB_OTG_Status OTGD_FS_WritePacket(uint8_t *src, uint8_t ch_ep_num, uint16_t bytes); - -USB_OTG_Status USB_OTG_HcInit(USB_OTG_HC *hc); -USB_OTG_Status USB_OTG_StartXfer(USB_OTG_HC *hc); - -uint32_t USB_OTG_ResetPort( void); - -uint32_t USB_OTG_ReadHPRT0(void); -uint32_t OTGD_FS_ReadDevAllInEPItr(void); -uint32_t OTGD_FS_ReadCoreItr(void); -uint32_t OTGD_FS_ReadOtgItr (void); -uint32_t USB_OTG_ReadHostAllChannels_intr (void); -uint8_t IsHostMode(void); -uint8_t IsDeviceMode(void); -USB_OTG_Status USB_OTG_HcInit(USB_OTG_HC *hc); -USB_OTG_Status USB_OTG_HcHalt(uint8_t hc_num); - -USB_OTG_Status OTGD_FS_FlushTxFifo (uint32_t num); -USB_OTG_Status OTGD_FS_FlushRxFifo (void); -USB_OTG_Status OTGD_FS_SetHostMode (void); - -USB_OTG_Status OTGD_FS_PhyInit(void); -USB_OTG_Status USB_OTG_HcStartXfer(USB_OTG_HC *hc); - -USB_OTG_Status OTGD_FS_CoreInitDev (void); -USB_OTG_Status OTGD_FS_EnableDevInt(void); -USB_OTG_Status OTGD_FS_EP0Activate(void); -USB_OTG_Status OTGD_FS_EPActivate(USB_OTG_EP *ep); -USB_OTG_Status OTGD_FS_EPDeactivate(USB_OTG_EP *ep); - -USB_OTG_Status OTGD_FS_EPStartXfer(USB_OTG_EP *ep); -USB_OTG_Status OTGD_FS_EP0StartXfer(USB_OTG_EP *ep); - -USB_OTG_Status OTGD_FS_EPSetStall(USB_OTG_EP *ep); -USB_OTG_Status OTGD_FS_EPClearStall(USB_OTG_EP *ep); -uint32_t OTGD_FS_ReadDevAllOutEp_itr(void); -uint32_t OTGD_FS_ReadDevOutEP_itr(USB_OTG_EP *ep); -uint32_t OTGD_FS_ReadDevAllInEPItr(void); - - -uint32_t OTGD_FS_Dev_GetEPStatus(USB_OTG_EP *ep); -void OTGD_FS_Dev_SetEPStatus(USB_OTG_EP *ep, uint32_t Status); -void OTGD_FS_Dev_SetRemoteWakeup(void); -void OTGD_FS_Dev_ResetRemoteWakeup(void); - -#endif /* STM32F10X_CL */ - -#endif -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - diff --git a/STM32_USB-FS-Device_Driver/inc/otgd_fs_dev.h b/STM32_USB-FS-Device_Driver/inc/otgd_fs_dev.h deleted file mode 100644 index d0c7554..0000000 --- a/STM32_USB-FS-Device_Driver/inc/otgd_fs_dev.h +++ /dev/null @@ -1,121 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otg_dev.h -* Author : STMicroelectronics -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : linking defines -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __OTG_DEV_H__ -#define __OTG_DEV_H__ - -#ifdef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x.h" -#include "usb_type.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ - -/* Endpoint types */ -#define OTG_DEV_EP_TYPE_CONTROL 0 -#define OTG_DEV_EP_TYPE_ISOC 1 -#define OTG_DEV_EP_TYPE_BULK 2 -#define OTG_DEV_EP_TYPE_INT 3 - -/* Endpoint Addresses (w/direction) */ -#define EP0_OUT 0x00 -#define EP0_IN 0x80 -#define EP1_OUT 0x01 -#define EP1_IN 0x81 -#define EP2_OUT 0x02 -#define EP2_IN 0x82 -#define EP3_OUT 0x03 -#define EP3_IN 0x83 - - -/*-*-*-*-*-*-*-*-*-* Replace the usb_regs.h defines -*-*-*-*-*-*-*-*-*-*-*-*-*/ -/* endpoints enumeration */ -#define ENDP0 ((uint8_t)0) -#define ENDP1 ((uint8_t)1) -#define ENDP2 ((uint8_t)2) -#define ENDP3 ((uint8_t)3) -#define ENDP4 ((uint8_t)4) -#define ENDP5 ((uint8_t)5) -#define ENDP6 ((uint8_t)6) -#define ENDP7 ((uint8_t)7) - -/* EP Transmit status defines */ -#define EP_TX_DIS DEV_EP_TX_DIS) /* EndPoint TX DISabled */ -#define EP_TX_STALL DEV_EP_TX_STALL /* EndPoint TX STALLed */ -#define EP_TX_NAK DEV_EP_TX_NAK /* EndPoint TX NAKed */ -#define EP_TX_VALID DEV_EP_TX_VALID /* EndPoint TX VALID */ - -/* EP Transmit status defines */ -#define EP_RX_DIS DEV_EP_RX_DIS /* EndPoint RX DISabled */ -#define EP_RX_STALL DEV_EP_RX_STALL /* EndPoint RX STALLed */ -#define EP_RX_NAK DEV_EP_RX_NAK /* EndPoint RX NAKed */ -#define EP_RX_VALID DEV_EP_RX_VALID /* EndPoint RX VALID */ -/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - -/* Exported macro ------------------------------------------------------------*/ -#define _GetEPTxStatus(bEpNum) ((uint16_t)OTG_DEV_GetEPTxStatus(bEpNum)) -#define _GetEPRxStatus(bEpNum) ((uint16_t)OTG_DEV_GetEPRxStatus(bEpNum)) - -#define _SetEPTxStatus(bEpNum,wState) (OTG_DEV_SetEPTxStatus(bEpNum, wState)) -#define _SetEPRxStatus(bEpNum,wState) (OTG_DEV_SetEPRxStatus(bEpNum, wState)) - -#define _SetEPTxValid(bEpNum) (OTG_DEV_SetEPTxStatus(bEpNum, EP_TX_VALID)) -#define _SetEPRxValid(bEpNum) (OTG_DEV_SetEPRxStatus(bEpNum, EP_RX_VALID)) - -#define _GetTxStallStatus(bEpNum) (OTG_DEV_GetEPTxStatus(bEpNum) == EP_TX_STALL) -#define _GetRxStallStatus(bEpNum) (OTG_DEV_GetEPRxStatus(bEpNum) == EP_RX_STALL) - -/* Define the callbacks for updating the USB state machine */ -#define OTGD_FS_DEVICE_RESET Device_Property.Reset() - -/* Exported define -----------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -void OTG_DEV_Init(void); -void OTG_DEV_EP_Init(uint8_t bEpAdd, uint8_t bEpType, uint16_t wEpMaxPackSize); - -void OTG_DEV_SetEPRxStatus(uint8_t bEpnum, uint32_t status); -void OTG_DEV_SetEPTxStatus(uint8_t bEpnum, uint32_t status); -uint32_t OTG_DEV_GetEPRxStatus(uint8_t bEpnum); -uint32_t OTG_DEV_GetEPTxStatus(uint8_t bEpnum); - -void USB_DevDisconnect(void); -void USB_DevConnect(void); - - -/*-*-*-*-*-*-*-*-*-* Replace the usb_regs.h prototypes *-*-*-*-*-*-*-*-*-*-*-*/ -void SetEPTxStatus(uint8_t bEpNum, uint16_t wState); -void SetEPRxStatus(uint8_t bEpNum, uint16_t wState); -uint16_t GetEPTxStatus(uint8_t bEpNum); -uint16_t GetEPRxStatus(uint8_t bEpNum); -void SetEPTxValid(uint8_t bEpNum); -void SetEPRxValid(uint8_t bEpNum); -uint16_t GetTxStallStatus(uint8_t bEpNum); -uint16_t GetRxStallStatus(uint8_t bEpNum); -void SetEPTxCount(uint8_t bEpNum, uint16_t wCount); -void SetEPRxCount(uint8_t bEpNum, uint16_t wCount); - -uint16_t ToWord(uint8_t, uint8_t); -uint16_t ByteSwap(uint16_t); -/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - -#endif /* STM32F10X_CL */ - -#endif /* __OTG_DEV_H__ */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - diff --git a/STM32_USB-FS-Device_Driver/inc/otgd_fs_int.h b/STM32_USB-FS-Device_Driver/inc/otgd_fs_int.h deleted file mode 100644 index b0b1281..0000000 --- a/STM32_USB-FS-Device_Driver/inc/otgd_fs_int.h +++ /dev/null @@ -1,54 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_int.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Endpoint interrupt's service routines prototypes. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_INT_H -#define __USB_INT_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -#ifdef STM32F10X_CL - -/* Interrupt Handlers functions */ -uint32_t OTGD_FS_Handle_ModeMismatch_ISR(void); -uint32_t OTGD_FS_Handle_Sof_ISR(void); -uint32_t OTGD_FS_Handle_RxStatusQueueLevel_ISR(void); -uint32_t OTGD_FS_Handle_NPTxFE_ISR(void); -uint32_t OTGD_FS_Handle_GInNakEff_ISR(void); -uint32_t OTGD_FS_Handle_GOutNakEff_ISR(void); -uint32_t OTGD_FS_Handle_EarlySuspend_ISR(void); -uint32_t OTGD_FS_Handle_USBSuspend_ISR(void); -uint32_t OTGD_FS_Handle_UsbReset_ISR(void); -uint32_t OTGD_FS_Handle_EnumDone_ISR(void); -uint32_t OTGD_FS_Handle_IsoOutDrop_ISR(void); -uint32_t OTGD_FS_Handle_EOPF_ISR(void); -uint32_t OTGD_FS_Handle_EPMismatch_ISR(void); -uint32_t OTGD_FS_Handle_InEP_ISR(void); -uint32_t OTGD_FS_Handle_OutEP_ISR(void); -uint32_t OTGD_FS_Handle_IncomplIsoIn_ISR(void); -uint32_t OTGD_FS_Handle_IncomplIsoOut_ISR(void); -uint32_t OTGD_FS_Handle_Wakeup_ISR(void); - -#endif /* STM32F10X_CL */ - -/* External variables --------------------------------------------------------*/ - -#endif /* __USB_INT_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/otgd_fs_pcd.h b/STM32_USB-FS-Device_Driver/inc/otgd_fs_pcd.h deleted file mode 100644 index 5255737..0000000 --- a/STM32_USB-FS-Device_Driver/inc/otgd_fs_pcd.h +++ /dev/null @@ -1,87 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_pcd.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Header file of the High Layer device mode interface and -* wrapping layer -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -#ifndef __USB_OTG_PCD_H__ -#define __USB_OTG_PCD_H__ - -#include "otgd_fs_regs.h" - -#define MAX_EP0_SIZE 0x40 -#define MAX_PACKET_SIZE 0x400 - - -#define USB_ENDPOINT_XFER_CONTROL 0 -#define USB_ENDPOINT_XFER_ISOC 1 -#define USB_ENDPOINT_XFER_BULK 2 -#define USB_ENDPOINT_XFER_INT 3 -#define USB_ENDPOINT_XFERTYPE_MASK 3 - - -/******************************************************************************** - ENUMERATION TYPE -********************************************************************************/ -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, - USB_SPEED_LOW, USB_SPEED_FULL, - USB_SPEED_HIGH -}; -/******************************************************************************** - Data structure type -********************************************************************************/ -typedef struct usb_ep_descriptor -{ - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - uint16_t wMaxPacketSize; - uint8_t bInterval; -} -EP_DESCRIPTOR , *PEP_DESCRIPTOR; -/******************************************************************************** - USBF LAYER UNION AND STRUCTURES -********************************************************************************/ -typedef struct USB_OTG_USBF -{ - - USB_OTG_EP ep0; - uint8_t ep0state; - USB_OTG_EP in_ep[ MAX_TX_FIFOS - 1]; - USB_OTG_EP out_ep[ MAX_TX_FIFOS - 1]; -} -USB_OTG_PCD_DEV , *USB_OTG_PCD_PDEV; -/******************************************************************************** - EXPORTED FUNCTION FROM THE USB_OTG LAYER -********************************************************************************/ -void OTGD_FS_PCD_Init(void); -void OTGD_FS_PCD_DevConnect (void); -void OTGD_FS_PCD_DevDisconnect (void); -void OTGD_FS_PCD_EP_SetAddress (uint8_t address); -uint32_t OTGD_FS_PCD_EP_Open(EP_DESCRIPTOR *epdesc); -uint32_t OTGD_FS_PCD_EP_Close ( uint8_t ep_addr); -uint32_t OTGD_FS_PCD_EP_Read ( uint8_t ep_addr, uint8_t *pbuf, uint32_t buf_len); -uint32_t OTGD_FS_PCD_EP_Write ( uint8_t ep_addr, uint8_t *pbuf, uint32_t buf_len); -uint32_t OTGD_FS_PCD_EP_Stall (uint8_t epnum); -uint32_t OTGD_FS_PCD_EP_ClrStall (uint8_t epnum); -uint32_t OTGD_FS_PCD_EP_Flush (uint8_t epnum); -uint32_t OTGD_FS_PCD_Handle_ISR(void); - -USB_OTG_EP* OTGD_FS_PCD_GetOutEP(uint32_t ep_num) ; -USB_OTG_EP* OTGD_FS_PCD_GetInEP(uint32_t ep_num); -void OTGD_FS_PCD_EP0_OutStart(void); - -#endif -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/otgd_fs_regs.h b/STM32_USB-FS-Device_Driver/inc/otgd_fs_regs.h deleted file mode 100644 index d98bae0..0000000 --- a/STM32_USB-FS-Device_Driver/inc/otgd_fs_regs.h +++ /dev/null @@ -1,1592 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_regs.h -* Author : STMicroelectronics -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : USB OTG IP hardware registers. -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -#ifndef __USB_OTG_REGS_H__ -#define __USB_OTG_REGS_H__ - -#ifdef STM32F10X_CL - -#include "stm32f10x.h" -#include "usb_type.h" - -#define USB_OTG_FS1_BASE_ADDR 0x50000000 - -#define USB_OTG_CORE_GLOBAL_REGS_OFFSET 0x000 -#define USB_OTG_DEV_GLOBAL_REG_OFFSET 0x800 -#define USB_OTG_DEV_IN_EP_REG_OFFSET 0x900 -#define USB_OTG_EP_REG_OFFSET 0x20 -#define USB_OTG_DEV_OUT_EP_REG_OFFSET 0xB00 -#define USB_OTG_HOST_GLOBAL_REG_OFFSET 0x400 -#define USB_OTG_HOST_PORT_REGS_OFFSET 0x440 -#define USB_OTG_HOST_CHAN_REGS_OFFSET 0x500 -#define USB_OTG_CHAN_REGS_OFFSET 0x20 -#define USB_OTG_PCGCCTL_OFFSET 0xE00 -#define USB_OTG_DATA_FIFO_OFFSET 0x1000 -#define USB_OTG_DATA_FIFO_SIZE 0x1000 - -#define MAX_PERIO_FIFOS 8 -#define MAX_TX_FIFOS 4 -#define MAX_EPS_CHANNELS 8 -/******************************************************************************* - * USB_OTG Core registers . - * The USB_OTG_core_regs structure defines the size - * and relative field offsets for the Core Global registers. - ******************************************************************************/ -typedef struct _USB_OTG_common_regs //000h -{ - - __IO uint32_t otg_ctl; /* USB_OTG Control and Status Register 000h*/ - __IO uint32_t otg_int; /* USB_OTG Interrupt Register 004h*/ - __IO uint32_t ahb_cfg; /* Core AHB Configuration Register 008h*/ - __IO uint32_t usb_cfg; /* Core USB Configuration Register 00Ch*/ - __IO uint32_t rst_ctl; /* Core Reset Register 010h*/ - __IO uint32_t int_sts; /* Core Interrupt Register 014h*/ - __IO uint32_t int_msk; /* Core Interrupt Mask Register 018h*/ - __IO uint32_t rx_stsr; /* Receive Sts Q Read Register 01Ch*/ - __IO uint32_t rx_stsp; /* Receive Sts Q Read & POP Register 020h*/ - __IO uint32_t rx_fifo_siz; /* Receive FIFO Size Register 024h*/ - __IO uint32_t np_tx_fifo_siz; /* Non Periodic Tx FIFO Size Register 028h*/ - __IO uint32_t np_tx_sts; /* Non Periodic Tx FIFO/Queue Sts reg 02Ch*/ - __IO uint32_t i2c_ctl; /* I2C Access Register 030h*/ - __IO uint32_t phy_vnd_ctl; /* PHY Vendor Control Register 034h*/ - __IO uint32_t gpio; /* General Purpose IO Register 038h*/ - __IO uint32_t usr_id; /* User ID Register 03Ch*/ - __IO uint32_t snps_id; /* Synopsys ID Register 040h*/ - __IO uint32_t hw_cfg1; /* User HW Config1 Register (RO) 044h*/ - __IO uint32_t hw_cfg2; /* User HW Config2 Register (RO) 048h*/ - __IO uint32_t hw_cfg3; /* User HW Config3 Register (RO) 04Ch*/ - __IO uint32_t hw_cfg4; /* User HW Config4 Register (RO) 050h*/ - uint32_t reserved[43]; /* Reserved 054h-0FFh*/ - __IO uint32_t host_p_tx_fifo_siz; /* Host Periodic Tx FIFO Size Reg 100h*/ - __IO uint32_t dev_p_tx_fsiz_dieptxf[15];/* dev Periodic Transmit FIFO */ - -} -USB_OTG_common_regs; - -/******************************************************************************* - * dev Registers - * dev Global Registers : Offsets 800h-BFFh - * The following structures define the size and relative field offsets - * for the dev Mode Registers. - * These registers are visible only in dev mode and must not be - * accessed in Host mode, as the results are unknown - ******************************************************************************/ -typedef struct _USB_OTG_dev_regs // 800h -{ - - __IO uint32_t dev_cfg; /* dev Configuration Register 800h*/ - __IO uint32_t dev_ctl; /* dev Control Register 804h*/ - __IO uint32_t dev_sts; /* dev Status Register (RO) 808h*/ - uint32_t reserved3; /* Reserved 80Ch*/ - __IO uint32_t dev_in_ep_msk; /* dev IN Endpoint Mask 810h*/ - __IO uint32_t dev_out_ep_msk; /* dev OUT Endpoint Mask 814h*/ - __IO uint32_t dev_all_int; /* dev All Endpoints Itr Reg 818h*/ - __IO uint32_t dev_all_int_msk; /* dev All Endpoints Itr Mask 81Ch*/ - uint32_t Reserved8; /* Reserved 820h*/ - __IO uint32_t Reserved9; /* Reserved 824h*/ - __IO uint32_t dev_vbus_dis; /* dev VBUS discharge Register 828h*/ - __IO uint32_t dev_vbus_pulse; /* dev VBUS Pulse Register 82Ch*/ - __IO uint32_t dev_thr_ctl; /* dev thr 830h*/ - __IO uint32_t dev_fifo_empty_msk; /* dev empty msk 834h*/ - -} -USB_OTG_dev_regs; -/******************************************************************************* - * dev Logical IN Endpoint-Specific Registers: Offsets 900h-AFCh - * There will be one set of endpoint registers per logical endpointimplemented. - * These registers are visible only in dev mode and must not be - * accessed in Host mode, as the results are unknown -*******************************************************************************/ -typedef struct _USB_OTG_dev_in_ep_regs -{ - __IO uint32_t dev_in_ep_ctl; /* dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h*/ - uint32_t reserved04; /* Reserved 900h + (ep_num * 20h) + 04h*/ - __IO uint32_t dev_in_ep_int; /* dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h*/ - uint32_t reserved0C; /* Reserved 900h + (ep_num * 20h) + 0Ch*/ - __IO uint32_t dev_in_ep_txfer_siz; /* IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h*/ - __IO uint32_t dev_in_ep_dma; /* IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h*/ - __IO uint32_t dev_tx_fifo_sts;/*IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h*/ - uint32_t reserved18; /* Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch*/ - -} -USB_OTG_dev_in_ep_regs; - -/******************************************************************************* - * dev Logical OUT Endpoint-Specific Registers Offsets: B00h-CFCh - * There will be one set of endpoint registers per logical endpoint - * implemented. - * These registers are visible only in dev mode and must not be - * accessed in Host mode, as the results are unknown -******************************************************************************/ -typedef struct _USB_OTG_dev_out_ep_regs -{ - __IO uint32_t dev_out_ep_ctl; /* dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h*/ - __IO uint32_t dev_out_ep_frm_nbr; /* dev OUT Endpoint Frame number B00h + (ep_num * 20h) + 04h*/ - __IO uint32_t dev_out_ep_int; /* dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h*/ - uint32_t reserved0C; /* Reserved B00h + (ep_num * 20h) + 0Ch*/ - __IO uint32_t dev_out_ep_txfer_siz; /* dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h*/ - __IO uint32_t dev_out_ep_dma; /* dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h*/ - uint32_t reserved18[2]; /* Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch*/ - -} -USB_OTG_dev_out_ep_regs; -/******************************************************************************* - * Host Mode Register Structures - * The Host Global Registers structure defines the size and relative - * field offsets for the Host Mode Global Registers. - * Host Global Registers offsets 400h-7FFh. -*******************************************************************************/ -typedef struct _USB_OTG_host_regs -{ - __IO uint32_t host_cfg; /* Host Configuration Register 400h*/ - __IO uint32_t host_frm_intrvl; /* Host Frame Interval Register 404h*/ - __IO uint32_t host_frm_nbr; /* Host Frame Nbr/Frame Remaining 408h*/ - uint32_t reserved40C; /* Reserved 40Ch*/ - __IO uint32_t host_p_tx_sts; /* Host Periodic Tx FIFO/ Queue Status 410h*/ - __IO uint32_t host_all_int; /* Host All Channels Interrupt Register 414h*/ - __IO uint32_t host_all_int_msk; /* Host All Channels Interrupt Mask 418h*/ - -} -USB_OTG_host_regs; - -/******************************************************************************* -* Host Channel Specific Registers 500h-5FCh -*******************************************************************************/ -typedef struct _USB_OTG_hc_regs -{ - - __IO uint32_t hc_char; - __IO uint32_t hc_split; - __IO uint32_t hc_int; - __IO uint32_t hc_int_msk; - __IO uint32_t hc_txfer_siz; - __IO uint32_t hc_dma; - uint32_t reserved[2]; - -} -USB_OTG_hc_regs; -/******************************************************************************* - * otg Core registers . - * The USB_OTG_core_regs structure defines the size - * and relative field offsets for the Core Global registers. - ******************************************************************************/ -typedef struct USB_OTG_core_regs //000h -{ - USB_OTG_common_regs *common_regs; - USB_OTG_dev_regs *dev_regs; - USB_OTG_host_regs *host_regs; - USB_OTG_dev_in_ep_regs *inep_regs[MAX_EPS_CHANNELS]; - USB_OTG_dev_out_ep_regs *outep_regs[MAX_EPS_CHANNELS]; - USB_OTG_hc_regs *hc_regs[MAX_EPS_CHANNELS]; - __IO uint32_t *hprt0; - __IO uint32_t *data_fifo[MAX_EPS_CHANNELS]; - __IO uint32_t *pcgcctl; - -} -USB_OTG_CORE_REGS , *pUSB_OTG_CORE_REGS; -/******************************************************************************/ - -typedef union _USB_OTG_OTG_ctl_data -{ - uint32_t d32; - struct - { -uint32_t sesreqscs : - 1; -uint32_t sesreq : - 1; -uint32_t reserved2_7 : - 6; -uint32_t hstnegscs : - 1; -uint32_t hnpreq : - 1; -uint32_t hstsethnpen : - 1; -uint32_t devhnpen : - 1; -uint32_t reserved12_15 : - 4; -uint32_t conidsts : - 1; -uint32_t reserved17 : - 1; -uint32_t asesvld : - 1; -uint32_t bsesvld : - 1; -uint32_t currmod : - 1; -uint32_t reserved21_31 : - 11; - } - b; -} USB_OTG_OTG_ctl_data; - -/******************************************************************************/ - -typedef union _USB_OTG_OTG_int_data -{ - uint32_t d32; - struct - { -uint32_t reserved0_1 : - 2; -uint32_t sesenddet : - 1; -uint32_t reserved3_7 : - 5; -uint32_t sesreqsucstschng : - 1; -uint32_t hstnegsucstschng : - 1; -uint32_t reserver10_16 : - 7; -uint32_t hstnegdet : - 1; -uint32_t adevtoutchng : - 1; -uint32_t debdone : - 1; -uint32_t reserved31_20 : - 12; - } - b; -} USB_OTG_OTG_int_data; - - -/******************************************************************************/ - - -typedef union _USB_OTG_ahb_cfg_data -{ - uint32_t d32; - struct - { -uint32_t glblintrmsk : - 1; -uint32_t hburstlen : - 4; -uint32_t dmaenable : - 1; -uint32_t reserved : - 1; -uint32_t nptxfemplvl_txfemplvl : - 1; -uint32_t ptxfemplvl : - 1; -uint32_t reserved9_31 : - 23; - } - b; -} USB_OTG_ahb_cfg_data; - -/******************************************************************************/ - -typedef union _USB_OTG_usb_cfg_data -{ - uint32_t d32; - struct - { -uint32_t toutcal : - 3; -uint32_t phyif : - 1; -uint32_t ulpi_utmi_sel : - 1; -uint32_t fsintf : - 1; -uint32_t physel : - 1; -uint32_t ddrsel : - 1; -uint32_t srpcap : - 1; -uint32_t hnpcap : - 1; -uint32_t usbtrdtim : - 4; -uint32_t nptxfrwnden : - 1; -uint32_t phylpwrclksel : - 1; -uint32_t otgutmifssel : - 1; -uint32_t ulpi_fsls : - 1; -uint32_t ulpi_auto_res : - 1; -uint32_t ulpi_clk_sus_m : - 1; -uint32_t ulpi_ext_vbus_drv : - 1; -uint32_t ulpi_int_vbus_indicator : - 1; -uint32_t term_sel_dl_pulse : - 1; -uint32_t reserved : - 6; -uint32_t force_host : - 1; -uint32_t force_dev : - 1; -uint32_t corrupt_tx : - 1; - } - b; -} USB_OTG_usb_cfg_data; -/******************************************************************************/ - -typedef union _USB_OTG_rst_ctl_data -{ - uint32_t d32; - struct - { -uint32_t csftrst : - 1; -uint32_t hsftrst : - 1; -uint32_t hstfrm : - 1; -uint32_t intknqflsh : - 1; -uint32_t rxfflsh : - 1; -uint32_t txfflsh : - 1; -uint32_t txfnum : - 5; -uint32_t reserved11_29 : - 19; -uint32_t dmareq : - 1; -uint32_t ahbidle : - 1; - } - b; -} USB_OTG_rst_ctl_data; - -/******************************************************************************/ - -typedef union _USB_OTG_int_msk_data -{ - uint32_t d32; - struct - { -uint32_t reserved0 : - 1; -uint32_t modemismatch : - 1; -uint32_t otgintr : - 1; -uint32_t sofintr : - 1; -uint32_t rxstsqlvl : - 1; -uint32_t nptxfempty : - 1; -uint32_t ginnakeff : - 1; -uint32_t goutnakeff : - 1; -uint32_t reserved8 : - 1; -uint32_t i2cintr : - 1; -uint32_t erlysuspend : - 1; -uint32_t usbsuspend : - 1; -uint32_t usbreset : - 1; -uint32_t enumdone : - 1; -uint32_t isooutdrop : - 1; -uint32_t eopframe : - 1; -uint32_t reserved16 : - 1; -uint32_t epmismatch : - 1; -uint32_t inepintr : - 1; -uint32_t outepintr : - 1; -uint32_t incomplisoin : - 1; -uint32_t incomplisoout : - 1; -uint32_t reserved22_23 : - 2; -uint32_t portintr : - 1; -uint32_t hcintr : - 1; -uint32_t ptxfempty : - 1; -uint32_t reserved27 : - 1; -uint32_t conidstschng : - 1; -uint32_t disconnect : - 1; -uint32_t sessreqintr : - 1; -uint32_t wkupintr : - 1; - } - b; -} USB_OTG_int_msk_data; - -/******************************************************************************/ - - -typedef union _USB_OTG_int_sts_data -{ - uint32_t d32; - struct - { -uint32_t curmode : - 1; -uint32_t modemismatch : - 1; -uint32_t otgintr : - 1; -uint32_t sofintr : - 1; -uint32_t rxstsqlvl : - 1; -uint32_t nptxfempty : - 1; -uint32_t ginnakeff : - 1; -uint32_t goutnakeff : - 1; -uint32_t reserved8 : - 1; -uint32_t i2cintr : - 1; -uint32_t erlysuspend : - 1; -uint32_t usbsuspend : - 1; -uint32_t usbreset : - 1; -uint32_t enumdone : - 1; -uint32_t isooutdrop : - 1; -uint32_t eopframe : - 1; -uint32_t intokenrx : - 1; -uint32_t epmismatch : - 1; -uint32_t inepint: - 1; -uint32_t outepintr : - 1; -uint32_t incomplisoin : - 1; -uint32_t incomplisoout : - 1; -uint32_t reserved22_23 : - 2; -uint32_t portintr : - 1; -uint32_t hcintr : - 1; -uint32_t ptxfempty : - 1; -uint32_t reserved27 : - 1; -uint32_t conidstschng : - 1; -uint32_t disconnect : - 1; -uint32_t sessreqintr : - 1; -uint32_t wkupintr : - 1; - } - b; -} USB_OTG_int_sts_data; - -/******************************************************************************/ -typedef union _USB_OTG_dev_rx_sts_data -{ - - uint32_t d32; - struct - { -uint32_t epnum : - 4; -uint32_t bcnt : - 11; -uint32_t dpid : - 2; -uint32_t pktsts : - 4; -uint32_t fn : - 4; -uint32_t reserved : - 7; - } - b; -} USB_OTG_dev_rx_sts_data; - -/******************************************************************************/ -typedef union _USB_OTG_host_rx_sts_data -{ - - uint32_t d32; - struct - { -uint32_t chnum : - 4; -uint32_t bcnt : - 11; -uint32_t dpid : - 2; -uint32_t pktsts : - 4; -uint32_t reserved : - 11; - } - b; -} USB_OTG_host_rx_sts_data; - -/******************************************************************************/ - -typedef union _USB_OTG_fifo_size_data -{ - uint32_t d32; - struct - { -uint32_t startaddr : - 16; -uint32_t depth : - 16; - } - b; -} USB_OTG_fifo_size_data; - -/******************************************************************************/ - -typedef union _USB_OTG_np_tx_sts_data -{ - uint32_t d32; - struct - { -uint32_t nptxfspcavail : - 16; -uint32_t nptxqspcavail : - 8; -uint32_t nptxqtop_terminate : - 1; -uint32_t nptxqtop_token : - 2; -uint32_t nptxqtop_chnep : - 4; -uint32_t reserved : - 1; - } - b; -} USB_OTG_np_tx_sts_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_tx_fifo_sts_data -{ - uint32_t d32; - struct - { -uint32_t txfspcavail : - 16; -uint32_t reserved : - 16; - } - b; -} USB_OTG_dev_tx_fifo_sts_data; - -/******************************************************************************/ -typedef union _USB_OTG_i2c_ctl_data -{ - - uint32_t d32; - struct - { -uint32_t rwdata : - 8; -uint32_t regaddr : - 8; -uint32_t addr : - 7; -uint32_t i2cen : - 1; -uint32_t ack : - 1; -uint32_t i2csuspctl : - 1; -uint32_t i2cdevaddr : - 2; -uint32_t dat_se0: - 1; -uint32_t reserved : - 1; -uint32_t rw : - 1; -uint32_t bsydne : - 1; - } - b; -} USB_OTG_i2c_ctl_data; - -/******************************************************************************/ - -typedef union _USB_OTG_gpio_data -{ - - uint32_t d32; - struct - { - /* input */ -uint32_t ovrcur : - 1; -uint32_t otgid : - 1; -uint32_t reserved_in : - 14; - /* Output */ -uint32_t pwdn : - 1; -uint32_t i2cifen : - 1; -uint32_t vbussensingA : - 1; -uint32_t vbussensingB : - 1; -uint32_t SOFouten : - 1; -uint32_t reserved_out : - 11; - } - b; -} USB_OTG_gpio_data; - - -/******************************************************************************/ - -typedef union _USB_OTG_hw_cfg1_data -{ - - uint32_t d32; - struct - { -uint32_t ep_dir0 : - 2; -uint32_t ep_dir1 : - 2; -uint32_t ep_dir2 : - 2; -uint32_t ep_dir3 : - 2; -uint32_t ep_dir4 : - 2; -uint32_t ep_dir5 : - 2; -uint32_t ep_dir6 : - 2; -uint32_t ep_dir7 : - 2; -uint32_t ep_dir8 : - 2; -uint32_t ep_dir9 : - 2; -uint32_t ep_dir10 : - 2; -uint32_t ep_dir11 : - 2; -uint32_t ep_dir12 : - 2; -uint32_t ep_dir13 : - 2; -uint32_t ep_dir14 : - 2; -uint32_t ep_dir15 : - 2; - } - b; -} USB_OTG_hw_cfg1_data; - -/******************************************************************************/ -typedef union _USB_OTG_hw_cfg2_data -{ - uint32_t d32; - struct - { -uint32_t op_mode : - 3; -uint32_t architecture : - 2; -uint32_t point2point : - 1; -uint32_t hs_phy_type : - 2; -uint32_t fs_phy_type : - 2; -uint32_t num_dev_ep : - 4; -uint32_t num_host_chan : - 4; -uint32_t perio_ep_supported : - 1; -uint32_t dynamic_fifo : - 1; -uint32_t rx_status_q_depth : - 2; -uint32_t nonperio_tx_q_depth : - 2; -uint32_t host_perio_tx_q_depth : - 2; -uint32_t dev_token_q_depth : - 5; -uint32_t reserved31 : - 1; - } - b; -} USB_OTG_hw_cfg2_data; - -/******************************************************************************/ - -typedef union _USB_OTG_hw_cfg3_data -{ - - uint32_t d32; - struct - { -uint32_t xfer_size_cntr_width : - 4; -uint32_t packet_size_cntr_width : - 3; -uint32_t otg_func : - 1; -uint32_t i2c : - 1; -uint32_t vendor_ctrl_if : - 1; -uint32_t optional_features : - 1; -uint32_t synch_reset_type : - 1; -uint32_t ahb_phy_clock_synch : - 1; -uint32_t reserved15_13 : - 3; -uint32_t dfifo_depth : - 16; - } - b; -} USB_OTG_hw_cfg3_data; - -/******************************************************************************/ - -typedef union _USB_OTG_hw_cfg4_data -{ - uint32_t d32; - struct - { -uint32_t num_dev_perio_in_ep : - 4; -uint32_t power_optimiz : - 1; -uint32_t min_ahb_freq : - 9; -uint32_t utmi_phy_data_width : - 2; -uint32_t num_dev_mode_ctrl_ep : - 4; -uint32_t iddig_filt_en : - 1; -uint32_t vbus_valid_filt_en : - 1; -uint32_t a_valid_filt_en : - 1; -uint32_t b_valid_filt_en : - 1; -uint32_t session_end_filt_en : - 1; -uint32_t ded_fifo_en : - 1; -uint32_t num_in_eps : - 4; -uint32_t reserved31_30 : - 2; - } - b; -} USB_OTG_hw_cfg4_data; - -/******************************************************************************/ -typedef union _USB_OTG_dev_cfg_data -{ - - uint32_t d32; - struct - { -uint32_t devspd : - 2; -uint32_t nzstsouthshk : - 1; -uint32_t reserved3 : - 1; -uint32_t devaddr : - 7; -uint32_t perfrint : - 2; -uint32_t reserved13_17 : - 5; -uint32_t epmscnt : - 4; - } - b; -} USB_OTG_dev_cfg_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_ctl_data -{ - - uint32_t d32; - struct - { -uint32_t rmtwkupsig : - 1; -uint32_t sftdiscon : - 1; -uint32_t gnpinnaksts : - 1; -uint32_t goutnaksts : - 1; -uint32_t tstctl : - 3; -uint32_t sgnpinnak : - 1; -uint32_t cgnpinnak : - 1; -uint32_t sgoutnak : - 1; -uint32_t cgoutnak : - 1; -uint32_t reserved : - 21; - } - b; -} USB_OTG_dev_ctl_data; - -/******************************************************************************/ -typedef union _USB_OTG_dev_sts_data -{ - - uint32_t d32; - struct - { -uint32_t suspsts : - 1; -uint32_t enumspd : - 2; -uint32_t errticerr : - 1; -uint32_t reserved4_7: - 4; -uint32_t soffn : - 14; -uint32_t reserved22_31 : - 10; - } - b; -} USB_OTG_dev_sts_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_in_ep_int_data -{ - - uint32_t d32; - struct - { -uint32_t xfercompl : - 1; -uint32_t epdisabled : - 1; -uint32_t ahberr : - 1; -uint32_t timeout : - 1; -uint32_t intktxfemp : - 1; -uint32_t intknepmis : - 1; -uint32_t inepnakeff : - 1; -uint32_t emptyintr : - 1; -uint32_t txfifoundrn : - 1; -uint32_t reserved08_31 : - 23; - } - b; -} USB_OTG_dev_in_ep_int_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_in_ep_int_data USB_OTG_dev_in_ep_msk_data; -/******************************************************************************/ - -typedef union _USB_OTG_dev_out_ep_int_data -{ - - uint32_t d32; - struct - { -uint32_t xfercompl : - 1; -uint32_t epdisabled : - 1; -uint32_t ahberr : - 1; -uint32_t setup : - 1; -uint32_t reserved04_31 : - 28; - } - b; -} USB_OTG_dev_out_ep_int_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_out_ep_int_data USB_OTG_dev_out_ep_msk_data; - -/******************************************************************************/ -typedef union _USB_OTG_dev_all_int_data -{ - - uint32_t d32; - struct - { -uint32_t in : - 16; -uint32_t out : - 16; - } - ep; - struct - { - /** IN Endpoint bits */ -uint32_t inep0 : - 1; -uint32_t inep1 : - 1; -uint32_t inep2 : - 1; -uint32_t inep3 : - 1; -uint32_t inep4 : - 1; -uint32_t inep5 : - 1; -uint32_t inep6 : - 1; -uint32_t inep7 : - 1; -uint32_t inep8 : - 1; -uint32_t inep9 : - 1; -uint32_t inep10 : - 1; -uint32_t inep11 : - 1; -uint32_t inep12 : - 1; -uint32_t inep13 : - 1; -uint32_t inep14 : - 1; -uint32_t inep15 : - 1; - /** OUT Endpoint bits */ -uint32_t outep0 : - 1; -uint32_t outep1 : - 1; -uint32_t outep2 : - 1; -uint32_t outep3 : - 1; -uint32_t outep4 : - 1; -uint32_t outep5 : - 1; -uint32_t outep6 : - 1; -uint32_t outep7 : - 1; -uint32_t outep8 : - 1; -uint32_t outep9 : - 1; -uint32_t outep10 : - 1; -uint32_t outep11 : - 1; -uint32_t outep12 : - 1; -uint32_t outep13 : - 1; -uint32_t outep14 : - 1; -uint32_t outep15 : - 1; - } - b; -} USB_OTG_dev_all_int_data; - -/******************************************************************************/ -typedef union _USB_OTG_token_qr1_data -{ - - uint32_t d32; - struct - { -uint32_t intknwptr : - 5; -uint32_t reserved05_06 : - 2; -uint32_t wrap_bit : - 1; -uint32_t epnums0_5 : - 24; - } - b; -} USB_OTG_token_qr1_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_thr_ctl_data -{ - - uint32_t d32; - struct - { -uint32_t non_iso_thr_en : - 1; -uint32_t iso_thr_en : - 1; -uint32_t tx_thr_len : - 9; -uint32_t reserved11_15 : - 5; -uint32_t rx_thr_en : - 1; -uint32_t rx_thr_len : - 9; -uint32_t reserved26_31 : - 6; - } - b; -} USB_OTG_dev_thr_ctl_data; - -/******************************************************************************/ -typedef union _USB_OTG_dev_ep_ctl_data -{ - - uint32_t d32; - struct - { -uint32_t mps : - 11; -uint32_t nextep : - 4; -uint32_t usbactep : - 1; -uint32_t dpid : - 1; -uint32_t naksts : - 1; -uint32_t eptype : - 2; -uint32_t snp : - 1; -uint32_t stall : - 1; -uint32_t txfnum : - 4; -uint32_t cnak : - 1; -uint32_t snak : - 1; -uint32_t setd0pid : - 1; -uint32_t setd1pid : - 1; -uint32_t epdis : - 1; -uint32_t epena : - 1; - } - b; -} USB_OTG_dev_ep_ctl_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_ep_txfer_siz_data -{ - - uint32_t d32; - struct - { -uint32_t xfersize : - 19; -uint32_t pktcnt : - 10; -uint32_t mc : - 2; -uint32_t reserved : - 1; - } - b; -} USB_OTG_dev_ep_txfer_siz_data; - -/******************************************************************************/ - -typedef union _USB_OTG_dev_ep_txfer_size0_data -{ - - uint32_t d32; - struct - { -uint32_t xfersize : - 7; -uint32_t reserved7_18 : - 12; -uint32_t pktcnt : - 1; -uint32_t reserved20_28 : - 9; -uint32_t supcnt : - 2; - uint32_t reserved31; - } - b; -} USB_OTG_dev_ep_txfer_size0_data; - -/******************************************************************************/ -typedef union _USB_OTG_host_cfg_data -{ - - uint32_t d32; - struct - { -uint32_t fslspclksel : - 2; -uint32_t fslssupp : - 1; - } - b; -} USB_OTG_host_cfg_data; - -/******************************************************************************/ - -typedef union _USB_OTG_Host_frm_intrvl_data -{ - uint32_t d32; - struct - { -uint32_t frint : - 16; -uint32_t reserved : - 16; - } - b; -} USB_OTG_Host_frm_intrvl_data; - -/******************************************************************************/ -#define HFNUM_MAX_FRNUM 0x3FFF -typedef union _USB_OTG_host_frm_nbr_data -{ - - uint32_t d32; - struct - { -uint32_t frnum : - 16; -uint32_t frrem : - 16; - } - b; -} USB_OTG_host_frm_nbr_data; - -/******************************************************************************/ - -typedef union _USB_OTG_host_perio_tx_sts_data -{ - - uint32_t d32; - struct - { -uint32_t ptxfspcavail : - 16; -uint32_t ptxqspcavail : - 8; -uint32_t ptxqtop_terminate : - 1; -uint32_t ptxqtop_token : - 2; -uint32_t ptxqtop_chnum : - 4; -uint32_t ptxqtop_odd : - 1; - } - b; -} USB_OTG_host_perio_tx_sts_data; - -/******************************************************************************/ -typedef union _USB_OTG_hprt0_data -{ - uint32_t d32; - struct - { -uint32_t prtconnsts : - 1; -uint32_t prtconndet : - 1; -uint32_t prtena : - 1; -uint32_t prtenchng : - 1; -uint32_t prtovrcurract : - 1; -uint32_t prtovrcurrchng : - 1; -uint32_t prtres : - 1; -uint32_t prtsusp : - 1; -uint32_t prtrst : - 1; -uint32_t reserved9 : - 1; -uint32_t prtlnsts : - 2; -uint32_t prtpwr : - 1; -uint32_t prttstctl : - 4; -uint32_t prtspd : - 2; -uint32_t reserved19_31 : - 13; - } - b; -} USB_OTG_hprt0_data; - -/******************************************************************************/ - -typedef union _USB_OTG_host_all_int_data -{ - uint32_t d32; - struct - { -uint32_t ch0 : - 1; -uint32_t ch1 : - 1; -uint32_t ch2 : - 1; -uint32_t ch3 : - 1; -uint32_t ch4 : - 1; -uint32_t ch5 : - 1; -uint32_t ch6 : - 1; -uint32_t ch7 : - 1; -uint32_t ch8 : - 1; -uint32_t ch9 : - 1; -uint32_t ch10 : - 1; -uint32_t ch11 : - 1; -uint32_t ch12 : - 1; -uint32_t ch13 : - 1; -uint32_t ch14 : - 1; -uint32_t ch15 : - 1; -uint32_t reserved : - 16; - } - b; - - struct - { -uint32_t chint : - 16; -uint32_t reserved : - 16; - } - b2; -} USB_OTG_host_all_int_data; - - -/******************************************************************************/ - -typedef union _USB_OTG_host_all_int_msk_data -{ - uint32_t d32; - struct - { -uint32_t ch0 : - 1; -uint32_t ch1 : - 1; -uint32_t ch2 : - 1; -uint32_t ch3 : - 1; -uint32_t ch4 : - 1; -uint32_t ch5 : - 1; -uint32_t ch6 : - 1; -uint32_t ch7 : - 1; -uint32_t ch8 : - 1; -uint32_t ch9 : - 1; -uint32_t ch10 : - 1; -uint32_t ch11 : - 1; -uint32_t ch12 : - 1; -uint32_t ch13 : - 1; -uint32_t ch14 : - 1; -uint32_t ch15 : - 1; -uint32_t reserved : - 16; - } - b; - - struct - { -uint32_t chint : - 16; -uint32_t reserved : - 16; - } - b2; -} USB_OTG_host_all_int_msk_data; - -/******************************************************************************/ - -typedef union _USB_OTG_hc_char_data -{ - - uint32_t d32; - struct - { -uint32_t mps : - 11; -uint32_t epnum : - 4; -uint32_t epdir : - 1; -uint32_t reserved : - 1; -uint32_t lspddev : - 1; -uint32_t eptype : - 2; -uint32_t multicnt : - 2; -uint32_t devaddr : - 7; -uint32_t oddfrm : - 1; -uint32_t chdis : - 1; -uint32_t chen : - 1; - } - b; -} USB_OTG_hc_char_data; - -/******************************************************************************/ -typedef union _USB_OTG_hc_splt_data -{ - - uint32_t d32; - struct - { -uint32_t prtaddr : - 7; -uint32_t hubaddr : - 7; -uint32_t xactpos : - 2; -uint32_t compsplt : - 1; -uint32_t reserved : - 14; -uint32_t spltena : - 1; - } - b; -} USB_OTG_hc_splt_data; - -/******************************************************************************/ - -typedef union _USB_OTG_hc_int_data -{ - uint32_t d32; - struct - { -uint32_t xfercomp : - 1; -uint32_t chhltd : - 1; -uint32_t ahberr : - 1; -uint32_t stall : - 1; -uint32_t nak : - 1; -uint32_t ack : - 1; -uint32_t nyet : - 1; -uint32_t xacterr : - 1; -uint32_t bblerr : - 1; -uint32_t frmovrun : - 1; -uint32_t datatglerr : - 1; -uint32_t reserved : - 21; - } - b; -} USB_OTG_hc_int_data; - -/******************************************************************************/ - - -typedef union _USB_OTG_hc_txfer_siz_data -{ - - uint32_t d32; - struct - { -uint32_t xfersize : - 19; -uint32_t pktcnt : - 10; -uint32_t pid : - 2; -uint32_t dopng : - 1; - } - b; -} USB_OTG_hc_txfer_siz_data; - -/******************************************************************************/ - -typedef union _USB_OTG_hc_int_msk_data -{ - - uint32_t d32; - struct - { -uint32_t xfercompl : - 1; -uint32_t chhltd : - 1; -uint32_t ahberr : - 1; -uint32_t stall : - 1; -uint32_t nak : - 1; -uint32_t ack : - 1; -uint32_t nyet : - 1; -uint32_t xacterr : - 1; -uint32_t bblerr : - 1; -uint32_t frmovrun : - 1; -uint32_t datatglerr : - 1; -uint32_t reserved : - 21; - } - b; -} USB_OTG_hc_int_msk_data; - -/******************************************************************************/ - -typedef union _USB_OTG_host_pcgcctl_data -{ - uint32_t d32; - struct - { -uint32_t stoppclk : - 1; -uint32_t gatehclk : - 1; -uint32_t pwrclmp : - 1; -uint32_t rstpdwnmodule : - 1; -uint32_t physuspended : - 1; -uint32_t reserved : - 27; - } - b; -} USB_OTG_host_pcgcctl_data; - -#endif /* STM32F10X_CL */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - -#endif diff --git a/STM32_USB-FS-Device_Driver/inc/usb_core.h b/STM32_USB-FS-Device_Driver/inc/usb_core.h deleted file mode 100644 index 0c62fcb..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_core.h +++ /dev/null @@ -1,243 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_core.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Standard protocol processing functions prototypes -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_CORE_H -#define __USB_CORE_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef enum _CONTROL_STATE -{ - WAIT_SETUP, /* 0 */ - SETTING_UP, /* 1 */ - IN_DATA, /* 2 */ - OUT_DATA, /* 3 */ - LAST_IN_DATA, /* 4 */ - LAST_OUT_DATA, /* 5 */ - WAIT_STATUS_IN, /* 7 */ - WAIT_STATUS_OUT, /* 8 */ - STALLED, /* 9 */ - PAUSE /* 10 */ -} CONTROL_STATE; /* The state machine states of a control pipe */ - -typedef struct OneDescriptor -{ - uint8_t *Descriptor; - uint16_t Descriptor_Size; -} -ONE_DESCRIPTOR, *PONE_DESCRIPTOR; -/* All the request process routines return a value of this type - If the return value is not SUCCESS or NOT_READY, - the software will STALL the correspond endpoint */ -typedef enum _RESULT -{ - USB_SUCCESS = 0, /* Process sucessfully */ - USB_ERROR, - USB_UNSUPPORT, - USB_NOT_READY /* The process has not been finished, endpoint will be - NAK to further rquest */ -} RESULT; - - -/*-*-*-*-*-*-*-*-*-*-* Definitions for endpoint level -*-*-*-*-*-*-*-*-*-*-*-*/ -typedef struct _ENDPOINT_INFO -{ - /* When send data out of the device, - CopyData() is used to get data buffer 'Length' bytes data - if Length is 0, - CopyData() returns the total length of the data - if the request is not supported, returns 0 - (NEW Feature ) - if CopyData() returns -1, the calling routine should not proceed - further and will resume the SETUP process by the class device - if Length is not 0, - CopyData() returns a pointer to indicate the data location - Usb_wLength is the data remain to be sent, - Usb_wOffset is the Offset of original data - When receive data from the host, - CopyData() is used to get user data buffer which is capable - of Length bytes data to copy data from the endpoint buffer. - if Length is 0, - CopyData() returns the available data length, - if Length is not 0, - CopyData() returns user buffer address - Usb_rLength is the data remain to be received, - Usb_rPointer is the Offset of data buffer - */ - uint16_t Usb_wLength; - uint16_t Usb_wOffset; - uint16_t PacketSize; - uint8_t *(*CopyData)(uint16_t Length); -}ENDPOINT_INFO; - -/*-*-*-*-*-*-*-*-*-*-*-* Definitions for device level -*-*-*-*-*-*-*-*-*-*-*-*/ - -typedef struct _DEVICE -{ - uint8_t Total_Endpoint; /* Number of endpoints that are used */ - uint8_t Total_Configuration;/* Number of configuration available */ -} -DEVICE; - -typedef union -{ - uint16_t w; - struct BW - { - uint8_t bb1; - uint8_t bb0; - } - bw; -} uint16_t_uint8_t; - -typedef struct _DEVICE_INFO -{ - uint8_t USBbmRequestType; /* bmRequestType */ - uint8_t USBbRequest; /* bRequest */ - uint16_t_uint8_t USBwValues; /* wValue */ - uint16_t_uint8_t USBwIndexs; /* wIndex */ - uint16_t_uint8_t USBwLengths; /* wLength */ - - uint8_t ControlState; /* of type CONTROL_STATE */ - uint8_t Current_Feature; - uint8_t Current_Configuration; /* Selected configuration */ - uint8_t Current_Interface; /* Selected interface of current configuration */ - uint8_t Current_AlternateSetting;/* Selected Alternate Setting of current - interface*/ - - ENDPOINT_INFO Ctrl_Info; -}DEVICE_INFO; - -typedef struct _DEVICE_PROP -{ - void (*Init)(void); /* Initialize the device */ - void (*Reset)(void); /* Reset routine of this device */ - - /* Device dependent process after the status stage */ - void (*Process_Status_IN)(void); - void (*Process_Status_OUT)(void); - - /* Procedure of process on setup stage of a class specified request with data stage */ - /* All class specified requests with data stage are processed in Class_Data_Setup - Class_Data_Setup() - responses to check all special requests and fills ENDPOINT_INFO - according to the request - If IN tokens are expected, then wLength & wOffset will be filled - with the total transferring bytes and the starting position - If OUT tokens are expected, then rLength & rOffset will be filled - with the total expected bytes and the starting position in the buffer - - If the request is valid, Class_Data_Setup returns SUCCESS, else UNSUPPORT - - CAUTION: - Since GET_CONFIGURATION & GET_INTERFACE are highly related to - the individual classes, they will be checked and processed here. - */ - RESULT (*Class_Data_Setup)(uint8_t RequestNo); - - /* Procedure of process on setup stage of a class specified request without data stage */ - /* All class specified requests without data stage are processed in Class_NoData_Setup - Class_NoData_Setup - responses to check all special requests and perform the request - - CAUTION: - Since SET_CONFIGURATION & SET_INTERFACE are highly related to - the individual classes, they will be checked and processed here. - */ - RESULT (*Class_NoData_Setup)(uint8_t RequestNo); - - /*Class_Get_Interface_Setting - This function is used by the file usb_core.c to test if the selected Interface - and Alternate Setting (uint8_t Interface, uint8_t AlternateSetting) are supported by - the application. - This function is writing by user. It should return "SUCCESS" if the Interface - and Alternate Setting are supported by the application or "UNSUPPORT" if they - are not supported. */ - - RESULT (*Class_Get_Interface_Setting)(uint8_t Interface, uint8_t AlternateSetting); - - uint8_t* (*GetDeviceDescriptor)(uint16_t Length); - uint8_t* (*GetConfigDescriptor)(uint16_t Length); - uint8_t* (*GetStringDescriptor)(uint16_t Length); - - uint8_t* RxEP_buffer; - uint8_t MaxPacketSize; - -}DEVICE_PROP; - -typedef struct _USER_STANDARD_REQUESTS -{ - void (*User_GetConfiguration)(void); /* Get Configuration */ - void (*User_SetConfiguration)(void); /* Set Configuration */ - void (*User_GetInterface)(void); /* Get Interface */ - void (*User_SetInterface)(void); /* Set Interface */ - void (*User_GetStatus)(void); /* Get Status */ - void (*User_ClearFeature)(void); /* Clear Feature */ - void (*User_SetEndPointFeature)(void); /* Set Endpoint Feature */ - void (*User_SetDeviceFeature)(void); /* Set Device Feature */ - void (*User_SetDeviceAddress)(void); /* Set Device Address */ -} -USER_STANDARD_REQUESTS; - -/* Exported constants --------------------------------------------------------*/ -#define Type_Recipient (pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT)) - -#define Usb_rLength Usb_wLength -#define Usb_rOffset Usb_wOffset - -#define USBwValue USBwValues.w -#define USBwValue0 USBwValues.bw.bb0 -#define USBwValue1 USBwValues.bw.bb1 -#define USBwIndex USBwIndexs.w -#define USBwIndex0 USBwIndexs.bw.bb0 -#define USBwIndex1 USBwIndexs.bw.bb1 -#define USBwLength USBwLengths.w -#define USBwLength0 USBwLengths.bw.bb0 -#define USBwLength1 USBwLengths.bw.bb1 - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -uint8_t Setup0_Process(void); -uint8_t Post0_Process(void); -uint8_t Out0_Process(void); -uint8_t In0_Process(void); - -RESULT Standard_SetEndPointFeature(void); -RESULT Standard_SetDeviceFeature(void); - -uint8_t *Standard_GetConfiguration(uint16_t Length); -RESULT Standard_SetConfiguration(void); -uint8_t *Standard_GetInterface(uint16_t Length); -RESULT Standard_SetInterface(void); -uint8_t *Standard_GetDescriptorData(uint16_t Length, PONE_DESCRIPTOR pDesc); - -uint8_t *Standard_GetStatus(uint16_t Length); -RESULT Standard_ClearFeature(void); -void SetDeviceAddress(uint8_t); -void NOP_Process(void); - -extern const DEVICE_PROP Device_Property; -extern const USER_STANDARD_REQUESTS User_Standard_Requests; -extern const DEVICE Device_Table; -extern DEVICE_INFO Device_Info; - -/* cells saving status during interrupt servicing */ -extern __IO uint16_t SaveRState; -extern __IO uint16_t SaveTState; - -#endif /* __USB_CORE_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_def.h b/STM32_USB-FS-Device_Driver/inc/usb_def.h deleted file mode 100644 index 292de68..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_def.h +++ /dev/null @@ -1,80 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_def.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Definitions related to USB Core -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_DEF_H -#define __USB_DEF_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef enum _RECIPIENT_TYPE -{ - DEVICE_RECIPIENT, /* Recipient device */ - INTERFACE_RECIPIENT, /* Recipient interface */ - ENDPOINT_RECIPIENT, /* Recipient endpoint */ - OTHER_RECIPIENT -} RECIPIENT_TYPE; - - -typedef enum _STANDARD_REQUESTS -{ - GET_STATUS = 0, - CLEAR_FEATURE, - RESERVED1, - SET_FEATURE, - RESERVED2, - SET_ADDRESS, - GET_DESCRIPTOR, - SET_DESCRIPTOR, - GET_CONFIGURATION, - SET_CONFIGURATION, - GET_INTERFACE, - SET_INTERFACE, - TOTAL_sREQUEST, /* Total number of Standard request */ - SYNCH_FRAME = 12 -} STANDARD_REQUESTS; - -/* Definition of "USBwValue" */ -typedef enum _DESCRIPTOR_TYPE -{ - DEVICE_DESCRIPTOR = 1, - CONFIG_DESCRIPTOR, - STRING_DESCRIPTOR, - INTERFACE_DESCRIPTOR, - ENDPOINT_DESCRIPTOR -} DESCRIPTOR_TYPE; - -/* Feature selector of a SET_FEATURE or CLEAR_FEATURE */ -typedef enum _FEATURE_SELECTOR -{ - ENDPOINT_STALL, - DEVICE_REMOTE_WAKEUP -} FEATURE_SELECTOR; - -/* Exported constants --------------------------------------------------------*/ -/* Definition of "USBbmRequestType" */ -#define REQUEST_TYPE 0x60 /* Mask to get request type */ -#define STANDARD_REQUEST 0x00 /* Standard request */ -#define CLASS_REQUEST 0x20 /* Class request */ -#define VENDOR_REQUEST 0x40 /* Vendor request */ - -#define RECIPIENT 0x1F /* Mask to get recipient */ - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -#endif /* __USB_DEF_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_init.h b/STM32_USB-FS-Device_Driver/inc/usb_init.h deleted file mode 100644 index c570f8a..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_init.h +++ /dev/null @@ -1,49 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_init.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Initialization routines & global variables -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_INIT_H -#define __USB_INIT_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -void USB_Init(void); - -/* External variables --------------------------------------------------------*/ -/* The number of current endpoint, it will be used to specify an endpoint */ -extern uint8_t EPindex; -/* The number of current device, it is an index to the Device_Table */ -/*extern uint8_t Device_no; */ -/* Points to the DEVICE_INFO structure of current device */ -/* The purpose of this register is to speed up the execution */ -extern DEVICE_INFO* pInformation; -/* Points to the DEVICE_PROP structure of current device */ -/* The purpose of this register is to speed up the execution */ -extern const DEVICE_PROP* pProperty; -/* Temporary save the state of Rx & Tx status. */ -/* Whenever the Rx or Tx state is changed, its value is saved */ -/* in this variable first and will be set to the EPRB or EPRA */ -/* at the end of interrupt process */ -extern const USER_STANDARD_REQUESTS *pUser_Standard_Requests; - -extern uint16_t SaveState ; -extern uint16_t wInterrupt_Mask; - -#endif /* __USB_INIT_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_int.h b/STM32_USB-FS-Device_Driver/inc/usb_int.h deleted file mode 100644 index 617c88d..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_int.h +++ /dev/null @@ -1,33 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_int.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Endpoint CTR (Low and High) interrupt's service routines -* prototypes -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_INT_H -#define __USB_INT_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -void CTR_LP(void); -void CTR_HP(void); - -/* External variables --------------------------------------------------------*/ - -#endif /* __USB_INT_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_lib.h b/STM32_USB-FS-Device_Driver/inc/usb_lib.h deleted file mode 100644 index 8d4d094..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_lib.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_lib.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : USB library include files -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_LIB_H -#define __USB_LIB_H - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x.h" -#include "usb_type.h" -#include "usb_regs.h" -#include "usb_def.h" -#include "usb_core.h" -#include "usb_init.h" -#ifndef STM32F10X_CL - #include "usb_mem.h" - #include "usb_int.h" -#endif /* STM32F10X_CL */ - -#include "usb_sil.h" - -#ifdef STM32F10X_CL - #include "otgd_fs_cal.h" - #include "otgd_fs_pcd.h" - #include "otgd_fs_dev.h" - #include "otgd_fs_int.h" -#endif /* STM32F10X_CL */ - - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -/* External variables --------------------------------------------------------*/ - -#endif /* __USB_LIB_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_mem.h b/STM32_USB-FS-Device_Driver/inc/usb_mem.h deleted file mode 100644 index 6b906d9..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_mem.h +++ /dev/null @@ -1,32 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_mem.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Utility prototypes functions for memory/PMA transfers -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_MEM_H -#define __USB_MEM_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes); -void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes); - -/* External variables --------------------------------------------------------*/ - -#endif /*__USB_MEM_H*/ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_regs.h b/STM32_USB-FS-Device_Driver/inc/usb_regs.h deleted file mode 100644 index e0ff108..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_regs.h +++ /dev/null @@ -1,670 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_regs.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Interface prototype functions to USB cell registers -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_REGS_H -#define __USB_REGS_H - -#ifndef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef enum _EP_DBUF_DIR -{ - /* double buffered endpoint direction */ - EP_DBUF_ERR, - EP_DBUF_OUT, - EP_DBUF_IN -}EP_DBUF_DIR; - -/* endpoint buffer number */ -enum EP_BUF_NUM -{ - EP_NOBUF, - EP_BUF0, - EP_BUF1 -}; - -/* Exported constants --------------------------------------------------------*/ -#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */ -#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */ - -/******************************************************************************/ -/* General registers */ -/******************************************************************************/ - -/* Control register */ -#define CNTR ((__IO unsigned *)(RegBase + 0x40)) -/* Interrupt status register */ -#define ISTR ((__IO unsigned *)(RegBase + 0x44)) -/* Frame number register */ -#define FNR ((__IO unsigned *)(RegBase + 0x48)) -/* Device address register */ -#define DADDR ((__IO unsigned *)(RegBase + 0x4C)) -/* Buffer Table address register */ -#define BTABLE ((__IO unsigned *)(RegBase + 0x50)) -/******************************************************************************/ -/* Endpoint registers */ -/******************************************************************************/ -#define EP0REG ((__IO unsigned *)(RegBase)) /* endpoint 0 register address */ - -/* Endpoint Addresses (w/direction) */ -#define EP0_OUT ((uint8_t)0x00) -#define EP0_IN ((uint8_t)0x80) -#define EP1_OUT ((uint8_t)0x01) -#define EP1_IN ((uint8_t)0x81) -#define EP2_OUT ((uint8_t)0x02) -#define EP2_IN ((uint8_t)0x82) -#define EP3_OUT ((uint8_t)0x03) -#define EP3_IN ((uint8_t)0x83) -#define EP4_OUT ((uint8_t)0x04) -#define EP4_IN ((uint8_t)0x84) -#define EP5_OUT ((uint8_t)0x05) -#define EP5_IN ((uint8_t)0x85) -#define EP6_OUT ((uint8_t)0x06) -#define EP6_IN ((uint8_t)0x86) -#define EP7_OUT ((uint8_t)0x07) -#define EP7_IN ((uint8_t)0x87) - -/* endpoints enumeration */ -#define ENDP0 ((uint8_t)0) -#define ENDP1 ((uint8_t)1) -#define ENDP2 ((uint8_t)2) -#define ENDP3 ((uint8_t)3) -#define ENDP4 ((uint8_t)4) -#define ENDP5 ((uint8_t)5) -#define ENDP6 ((uint8_t)6) -#define ENDP7 ((uint8_t)7) - -/******************************************************************************/ -/* ISTR interrupt events */ -/******************************************************************************/ -#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ -#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ -#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ -#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ -#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ -#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ -#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ -#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ - - -#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ -#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ - -#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ -#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ -#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ -#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ -#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ -#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ -#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ -#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ - -/******************************************************************************/ -/* CNTR control register bits definitions */ -/******************************************************************************/ -#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ -#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ -#define CNTR_ERRM (0x2000) /* ERRor Mask */ -#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ -#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ -#define CNTR_RESETM (0x0400) /* RESET Mask */ -#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ -#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ - - -#define CNTR_RESUME (0x0010) /* RESUME request */ -#define CNTR_FSUSP (0x0008) /* Force SUSPend */ -#define CNTR_LPMODE (0x0004) /* Low-power MODE */ -#define CNTR_PDWN (0x0002) /* Power DoWN */ -#define CNTR_FRES (0x0001) /* Force USB RESet */ - -/******************************************************************************/ -/* FNR Frame Number Register bit definitions */ -/******************************************************************************/ -#define FNR_RXDP (0x8000) /* status of D+ data line */ -#define FNR_RXDM (0x4000) /* status of D- data line */ -#define FNR_LCK (0x2000) /* LoCKed */ -#define FNR_LSOF (0x1800) /* Lost SOF */ -#define FNR_FN (0x07FF) /* Frame Number */ -/******************************************************************************/ -/* DADDR Device ADDRess bit definitions */ -/******************************************************************************/ -#define DADDR_EF (0x80) -#define DADDR_ADD (0x7F) -/******************************************************************************/ -/* Endpoint register */ -/******************************************************************************/ -/* bit positions */ -#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ -#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ -#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ -#define EP_SETUP (0x0800) /* EndPoint SETUP */ -#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ -#define EP_KIND (0x0100) /* EndPoint KIND */ -#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ -#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ -#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ -#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ - -/* EndPoint REGister MASK (no toggle fields) */ -#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) - -/* EP_TYPE[1:0] EndPoint TYPE */ -#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */ -#define EP_BULK (0x0000) /* EndPoint BULK */ -#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ -#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ -#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ -#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK) - - -/* EP_KIND EndPoint KIND */ -#define EPKIND_MASK (~EP_KIND & EPREG_MASK) - -/* STAT_TX[1:0] STATus for TX transfer */ -#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ -#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ -#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ -#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ -#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ -#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ -#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK) - -/* STAT_RX[1:0] STATus for RX transfer */ -#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ -#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ -#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ -#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ -#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ -#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ -#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK) -/* Exported macro ------------------------------------------------------------*/ -/* SetCNTR */ -#define _SetCNTR(wRegValue) (*CNTR = (uint16_t)wRegValue) - -/* SetISTR */ -#define _SetISTR(wRegValue) (*ISTR = (uint16_t)wRegValue) - -/* SetDADDR */ -#define _SetDADDR(wRegValue) (*DADDR = (uint16_t)wRegValue) - -/* SetBTABLE */ -#define _SetBTABLE(wRegValue)(*BTABLE = (uint16_t)(wRegValue & 0xFFF8)) - -/* GetCNTR */ -#define _GetCNTR() ((uint16_t) *CNTR) - -/* GetISTR */ -#define _GetISTR() ((uint16_t) *ISTR) - -/* GetFNR */ -#define _GetFNR() ((uint16_t) *FNR) - -/* GetDADDR */ -#define _GetDADDR() ((uint16_t) *DADDR) - -/* GetBTABLE */ -#define _GetBTABLE() ((uint16_t) *BTABLE) - -/* SetENDPOINT */ -#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \ - (uint16_t)wRegValue) - -/* GetENDPOINT */ -#define _GetENDPOINT(bEpNum) ((uint16_t)(*(EP0REG + bEpNum))) - -/******************************************************************************* -* Macro Name : SetEPType -* Description : sets the type in the endpoint register(bits EP_TYPE[1:0]) -* Input : bEpNum: Endpoint Number. -* wType -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\ - ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType ))) - -/******************************************************************************* -* Macro Name : GetEPType -* Description : gets the type in the endpoint register(bits EP_TYPE[1:0]) -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Type -*******************************************************************************/ -#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD) - -/******************************************************************************* -* Macro Name : SetEPTxStatus -* Description : sets the status for tx transfer (bits STAT_TX[1:0]). -* Input : bEpNum: Endpoint Number. -* wState: new state -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxStatus(bEpNum,wState) {\ - register uint16_t _wRegVal; \ - _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\ - /* toggle first bit ? */ \ - if((EPTX_DTOG1 & wState)!= 0) \ - _wRegVal ^= EPTX_DTOG1; \ - /* toggle second bit ? */ \ - if((EPTX_DTOG2 & wState)!= 0) \ - _wRegVal ^= EPTX_DTOG2; \ - _SetENDPOINT(bEpNum, (_wRegVal | EP_CTR_RX|EP_CTR_TX)); \ - } /* _SetEPTxStatus */ - -/******************************************************************************* -* Macro Name : SetEPRxStatus -* Description : sets the status for rx transfer (bits STAT_TX[1:0]) -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPRxStatus(bEpNum,wState) {\ - register uint16_t _wRegVal; \ - \ - _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\ - /* toggle first bit ? */ \ - if((EPRX_DTOG1 & wState)!= 0) \ - _wRegVal ^= EPRX_DTOG1; \ - /* toggle second bit ? */ \ - if((EPRX_DTOG2 & wState)!= 0) \ - _wRegVal ^= EPRX_DTOG2; \ - _SetENDPOINT(bEpNum, (_wRegVal | EP_CTR_RX|EP_CTR_TX)); \ - } /* _SetEPRxStatus */ - -/******************************************************************************* -* Macro Name : SetEPRxTxStatus -* Description : sets the status for rx & tx (bits STAT_TX[1:0] & STAT_RX[1:0]) -* Input : bEpNum: Endpoint Number. -* wStaterx: new state. -* wStatetx: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPRxTxStatus(bEpNum,wStaterx,wStatetx) {\ - register uint32_t _wRegVal; \ - \ - _wRegVal = _GetENDPOINT(bEpNum) & (EPRX_DTOGMASK |EPTX_STAT) ;\ - /* toggle first bit ? */ \ - if((EPRX_DTOG1 & wStaterx)!= 0) \ - _wRegVal ^= EPRX_DTOG1; \ - /* toggle second bit ? */ \ - if((EPRX_DTOG2 & wStaterx)!= 0) \ - _wRegVal ^= EPRX_DTOG2; \ - /* toggle first bit ? */ \ - if((EPTX_DTOG1 & wStatetx)!= 0) \ - _wRegVal ^= EPTX_DTOG1; \ - /* toggle second bit ? */ \ - if((EPTX_DTOG2 & wStatetx)!= 0) \ - _wRegVal ^= EPTX_DTOG2; \ - _SetENDPOINT(bEpNum, _wRegVal | EP_CTR_RX|EP_CTR_TX); \ - } /* _SetEPRxTxStatus */ -/******************************************************************************* -* Macro Name : GetEPTxStatus / GetEPRxStatus -* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0] -* /STAT_RX[1:0]) -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : status . -*******************************************************************************/ -#define _GetEPTxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPTX_STAT) - -#define _GetEPRxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPRX_STAT) - -/******************************************************************************* -* Macro Name : SetEPTxValid / SetEPRxValid -* Description : sets directly the VALID tx/rx-status into the enpoint register -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID)) - -#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID)) - -/******************************************************************************* -* Macro Name : GetTxStallStatus / GetRxStallStatus. -* Description : checks stall condition in an endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : TRUE = endpoint in stall condition. -*******************************************************************************/ -#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \ - == EP_TX_STALL) -#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \ - == EP_RX_STALL) - -/******************************************************************************* -* Macro Name : SetEP_KIND / ClearEP_KIND. -* Description : set & clear EP_KIND bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ - (EP_CTR_RX|EP_CTR_TX|((_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK)))) -#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ - (EP_CTR_RX|EP_CTR_TX|(_GetENDPOINT(bEpNum) & EPKIND_MASK)))) - -/******************************************************************************* -* Macro Name : Set_Status_Out / Clear_Status_Out. -* Description : Sets/clears directly STATUS_OUT bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum) -#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum) - -/******************************************************************************* -* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff. -* Description : Sets/clears directly EP_KIND bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum) -#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum) - -/******************************************************************************* -* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX. -* Description : Clears bit CTR_RX / CTR_TX in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\ - _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK)) -#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\ - _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK)) - -/******************************************************************************* -* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX . -* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \ - EP_CTR_RX|EP_CTR_TX|EP_DTOG_RX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) -#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \ - EP_CTR_RX|EP_CTR_TX|EP_DTOG_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) - -/******************************************************************************* -* Macro Name : ClearDTOG_RX / ClearDTOG_TX. -* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\ - _ToggleDTOG_RX(bEpNum) -#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\ - _ToggleDTOG_TX(bEpNum) -/******************************************************************************* -* Macro Name : SetEPAddress. -* Description : Sets address in an endpoint register. -* Input : bEpNum: Endpoint Number. -* bAddr: Address. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\ - EP_CTR_RX|EP_CTR_TX|(_GetENDPOINT(bEpNum) & EPREG_MASK) | bAddr) - -/******************************************************************************* -* Macro Name : GetEPAddress. -* Description : Gets address in an endpoint register. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _GetEPAddress(bEpNum) ((uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD)) - -#define _pEPTxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) -#define _pEPTxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) -#define _pEPRxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) -#define _pEPRxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) - -/******************************************************************************* -* Macro Name : SetEPTxAddr / SetEPRxAddr. -* Description : sets address of the tx/rx buffer. -* Input : bEpNum: Endpoint Number. -* wAddr: address to be set (must be word aligned). -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1)) -#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1)) - -/******************************************************************************* -* Macro Name : GetEPTxAddr / GetEPRxAddr. -* Description : Gets address of the tx/rx buffer. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : address of the buffer. -*******************************************************************************/ -#define _GetEPTxAddr(bEpNum) ((uint16_t)*_pEPTxAddr(bEpNum)) -#define _GetEPRxAddr(bEpNum) ((uint16_t)*_pEPRxAddr(bEpNum)) - -/******************************************************************************* -* Macro Name : SetEPCountRxReg. -* Description : Sets counter of rx buffer with no. of blocks. -* Input : pdwReg: pointer to counter. -* wCount: Counter. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _BlocksOf32(dwReg,wCount,wNBlocks) {\ - wNBlocks = wCount >> 5;\ - if((wCount & 0x1f) == 0)\ - wNBlocks--;\ - *pdwReg = (uint32_t)((wNBlocks << 10) | 0x8000);\ - }/* _BlocksOf32 */ - -#define _BlocksOf2(dwReg,wCount,wNBlocks) {\ - wNBlocks = wCount >> 1;\ - if((wCount & 0x1) != 0)\ - wNBlocks++;\ - *pdwReg = (uint32_t)(wNBlocks << 10);\ - }/* _BlocksOf2 */ - -#define _SetEPCountRxReg(dwReg,wCount) {\ - uint16_t wNBlocks;\ - if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\ - else {_BlocksOf2(dwReg,wCount,wNBlocks);}\ - }/* _SetEPCountRxReg */ - - - -#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\ - uint32_t *pdwReg = _pEPTxCount(bEpNum); \ - _SetEPCountRxReg(pdwReg, wCount);\ - } -/******************************************************************************* -* Macro Name : SetEPTxCount / SetEPRxCount. -* Description : sets counter for the tx/rx buffer. -* Input : bEpNum: endpoint number. -* wCount: Counter value. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount) -#define _SetEPRxCount(bEpNum,wCount) {\ - uint32_t *pdwReg = _pEPRxCount(bEpNum); \ - _SetEPCountRxReg(pdwReg, wCount);\ - } -/******************************************************************************* -* Macro Name : GetEPTxCount / GetEPRxCount. -* Description : gets counter of the tx buffer. -* Input : bEpNum: endpoint number. -* Output : None. -* Return : Counter value. -*******************************************************************************/ -#define _GetEPTxCount(bEpNum)((uint16_t)(*_pEPTxCount(bEpNum)) & 0x3ff) -#define _GetEPRxCount(bEpNum)((uint16_t)(*_pEPRxCount(bEpNum)) & 0x3ff) - -/******************************************************************************* -* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr. -* Description : Sets buffer 0/1 address in a double buffer endpoint. -* Input : bEpNum: endpoint number. -* : wBuf0Addr: buffer 0 address. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);} -#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);} - -/******************************************************************************* -* Macro Name : SetEPDblBuffAddr. -* Description : Sets addresses in a double buffer endpoint. -* Input : bEpNum: endpoint number. -* : wBuf0Addr: buffer 0 address. -* : wBuf1Addr = buffer 1 address. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \ - _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\ - _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\ - } /* _SetEPDblBuffAddr */ - -/******************************************************************************* -* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr. -* Description : Gets buffer 0/1 address of a double buffer endpoint. -* Input : bEpNum: endpoint number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum)) -#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum)) - -/******************************************************************************* -* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count. -* Description : Gets buffer 0/1 address of a double buffer endpoint. -* Input : bEpNum: endpoint number. -* : bDir: endpoint dir EP_DBUF_OUT = OUT -* EP_DBUF_IN = IN -* : wCount: Counter value -* Output : None. -* Return : None. -*******************************************************************************/ -#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \ - if(bDir == EP_DBUF_OUT)\ - /* OUT endpoint */ \ - {_SetEPRxDblBuf0Count(bEpNum,wCount);} \ - else if(bDir == EP_DBUF_IN)\ - /* IN endpoint */ \ - *_pEPTxCount(bEpNum) = (uint32_t)wCount; \ - } /* SetEPDblBuf0Count*/ - -#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \ - if(bDir == EP_DBUF_OUT)\ - /* OUT endpoint */ \ - {_SetEPRxCount(bEpNum,wCount);}\ - else if(bDir == EP_DBUF_IN)\ - /* IN endpoint */\ - *_pEPRxCount(bEpNum) = (uint32_t)wCount; \ - } /* SetEPDblBuf1Count */ - -#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\ - _SetEPDblBuf0Count(bEpNum, bDir, wCount); \ - _SetEPDblBuf1Count(bEpNum, bDir, wCount); \ - } /* _SetEPDblBuffCount */ - -/******************************************************************************* -* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count. -* Description : Gets buffer 0/1 rx/tx counter for double buffering. -* Input : bEpNum: endpoint number. -* Output : None. -* Return : None. -*******************************************************************************/ -#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum)) -#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum)) - - -/* External variables --------------------------------------------------------*/ -extern __IO uint16_t wIstr; /* ISTR register last read value */ - -/* Exported functions ------------------------------------------------------- */ -void SetCNTR(uint16_t /*wRegValue*/); -void SetISTR(uint16_t /*wRegValue*/); -void SetDADDR(uint16_t /*wRegValue*/); -void SetBTABLE(uint16_t /*wRegValue*/); -uint16_t GetCNTR(void); -uint16_t GetISTR(void); -uint16_t GetFNR(void); -uint16_t GetDADDR(void); -uint16_t GetBTABLE(void); -void SetENDPOINT(uint8_t /*bEpNum*/, uint16_t /*wRegValue*/); -uint16_t GetENDPOINT(uint8_t /*bEpNum*/); -void SetEPType(uint8_t /*bEpNum*/, uint16_t /*wType*/); -uint16_t GetEPType(uint8_t /*bEpNum*/); -void SetEPTxStatus(uint8_t /*bEpNum*/, uint16_t /*wState*/); -void SetEPRxStatus(uint8_t /*bEpNum*/, uint16_t /*wState*/); -void SetDouBleBuffEPStall(uint8_t /*bEpNum*/, uint8_t bDir); -uint16_t GetEPTxStatus(uint8_t /*bEpNum*/); -uint16_t GetEPRxStatus(uint8_t /*bEpNum*/); -void SetEPTxValid(uint8_t /*bEpNum*/); -void SetEPRxValid(uint8_t /*bEpNum*/); -uint16_t GetTxStallStatus(uint8_t /*bEpNum*/); -uint16_t GetRxStallStatus(uint8_t /*bEpNum*/); -void SetEP_KIND(uint8_t /*bEpNum*/); -void ClearEP_KIND(uint8_t /*bEpNum*/); -void Set_Status_Out(uint8_t /*bEpNum*/); -void Clear_Status_Out(uint8_t /*bEpNum*/); -void SetEPDoubleBuff(uint8_t /*bEpNum*/); -void ClearEPDoubleBuff(uint8_t /*bEpNum*/); -void ClearEP_CTR_RX(uint8_t /*bEpNum*/); -void ClearEP_CTR_TX(uint8_t /*bEpNum*/); -void ToggleDTOG_RX(uint8_t /*bEpNum*/); -void ToggleDTOG_TX(uint8_t /*bEpNum*/); -void ClearDTOG_RX(uint8_t /*bEpNum*/); -void ClearDTOG_TX(uint8_t /*bEpNum*/); -void SetEPAddress(uint8_t /*bEpNum*/, uint8_t /*bAddr*/); -uint8_t GetEPAddress(uint8_t /*bEpNum*/); -void SetEPTxAddr(uint8_t /*bEpNum*/, uint16_t /*wAddr*/); -void SetEPRxAddr(uint8_t /*bEpNum*/, uint16_t /*wAddr*/); -uint16_t GetEPTxAddr(uint8_t /*bEpNum*/); -uint16_t GetEPRxAddr(uint8_t /*bEpNum*/); -void SetEPCountRxReg(uint32_t * /*pdwReg*/, uint16_t /*wCount*/); -void SetEPTxCount(uint8_t /*bEpNum*/, uint16_t /*wCount*/); -void SetEPRxCount(uint8_t /*bEpNum*/, uint16_t /*wCount*/); -uint16_t GetEPTxCount(uint8_t /*bEpNum*/); -uint16_t GetEPRxCount(uint8_t /*bEpNum*/); -void SetEPDblBuf0Addr(uint8_t /*bEpNum*/, uint16_t /*wBuf0Addr*/); -void SetEPDblBuf1Addr(uint8_t /*bEpNum*/, uint16_t /*wBuf1Addr*/); -void SetEPDblBuffAddr(uint8_t /*bEpNum*/, uint16_t /*wBuf0Addr*/, uint16_t /*wBuf1Addr*/); -uint16_t GetEPDblBuf0Addr(uint8_t /*bEpNum*/); -uint16_t GetEPDblBuf1Addr(uint8_t /*bEpNum*/); -void SetEPDblBuffCount(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); -void SetEPDblBuf0Count(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); -void SetEPDblBuf1Count(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); -uint16_t GetEPDblBuf0Count(uint8_t /*bEpNum*/); -uint16_t GetEPDblBuf1Count(uint8_t /*bEpNum*/); -EP_DBUF_DIR GetEPDblBufDir(uint8_t /*bEpNum*/); -void FreeUserBuffer(uint8_t bEpNum/*bEpNum*/, uint8_t bDir); -uint16_t ToWord(uint8_t, uint8_t); -uint16_t ByteSwap(uint16_t); - -#endif /* STM32F10X_CL */ - -#endif /* __USB_REGS_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_sil.h b/STM32_USB-FS-Device_Driver/inc/usb_sil.h deleted file mode 100644 index af4884f..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_sil.h +++ /dev/null @@ -1,34 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_sil.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Simplified Interface Layer function prototypes. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_SIL_H -#define __USB_SIL_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -uint32_t USB_SIL_Init(void); -uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize); -uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer); - -/* External variables --------------------------------------------------------*/ - -#endif /* __USB_SIL_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/inc/usb_type.h b/STM32_USB-FS-Device_Driver/inc/usb_type.h deleted file mode 100644 index 8b8bd25..0000000 --- a/STM32_USB-FS-Device_Driver/inc/usb_type.h +++ /dev/null @@ -1,74 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_type.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Type definitions used by the USB Library -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_TYPE_H -#define __USB_TYPE_H - -/* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -#ifndef NULL -#define NULL ((void *)0) -#endif - -#ifndef __STM32F10x_H - -typedef signed long s32; -typedef signed short s16; -typedef signed char s8; - -typedef volatile signed long vs32; -typedef volatile signed short vs16; -typedef volatile signed char vs8; - -typedef unsigned long u32; -typedef unsigned short u16; -typedef unsigned char u8; - -typedef unsigned long const uc32; /* Read Only */ -typedef unsigned short const uc16; /* Read Only */ -typedef unsigned char const uc8; /* Read Only */ - -typedef volatile unsigned long vu32; -typedef volatile unsigned short vu16; -typedef volatile unsigned char vu8; - -typedef volatile unsigned long const vuc32; /* Read Only */ -typedef volatile unsigned short const vuc16; /* Read Only */ -typedef volatile unsigned char const vuc8; /* Read Only */ - - -typedef enum -{ - FALSE = 0, TRUE = !FALSE -} -bool; - -typedef enum { RESET = 0, SET = !RESET } FlagStatus, ITStatus; - -typedef enum { DISABLE = 0, ENABLE = !DISABLE} FunctionalState; - -typedef enum { ERROR = 0, SUCCESS = !ERROR} ErrorStatus; -#endif -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -/* External variables --------------------------------------------------------*/ - -#endif /* __USB_TYPE_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/otgd_fs_cal.c b/STM32_USB-FS-Device_Driver/src/otgd_fs_cal.c deleted file mode 100644 index 7944cb7..0000000 --- a/STM32_USB-FS-Device_Driver/src/otgd_fs_cal.c +++ /dev/null @@ -1,1334 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_cal.c -* Author : STMicroelectronics -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : OTG FS Device Core Access Layer interface. -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -#ifdef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "otgd_fs_cal.h" -#include "usb_conf.h" -#include "otgd_fs_regs.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ - -USB_OTG_CORE_REGS core_regs; - -/* Private function prototypes -----------------------------------------------*/ -static uint32_t GetMode(void); -static void EnableCommonInt(void); -static USB_OTG_Status SetID(void); -static USB_OTG_Status OTGD_FS_CoreReset(void); - -extern uint32_t STM32_USBH_OTG_ISR_Handler (void); -extern uint32_t STM32_PCD_OTG_ISR_Handler (void); -extern uint32_t STM32_USBO_OTG_ISR_Handler (void); - -#ifdef HOST_MODE_ENABLED -static void InitFSLSPClkSel(void); -#endif - - -/******************************************************************************/ -/* Common Core Layer */ -/******************************************************************************/ - -/******************************************************************************* -* Function Name : OTGD_FS_PhyInit -* Description : Initialize the phy -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_PhyInit(void) -{ - USB_OTG_gpio_data gpioctl; - USB_OTG_usb_cfg_data usbcfg; - USB_OTG_Status status = USB_OTG_OK; - - gpioctl.d32 = 0; - usbcfg.d32 = 0; - - /* Enable the I2C interface and deactivate the power down*/ - gpioctl.d32 = 0; - gpioctl.b.vbussensingB = 1; - gpioctl.b.pwdn = 1; - gpioctl.b.i2cifen = 0; - WRITE_REG32 (&core_regs.common_regs->gpio, gpioctl.d32); - mDELAY(200); - - /* Program GUSBCFG.OtgUtmifsSel to I2C*/ - usbcfg.d32 = READ_REG32(&core_regs.common_regs->usb_cfg); - usbcfg.b.otgutmifssel = 0; - WRITE_REG32 (&core_regs.common_regs->usb_cfg, usbcfg.d32); - - return status; -} -/******************************************************************************* -* Function Name : OTGD_FS_WritePacket -* Description : Writes a packet into the Tx FIFO associated with the EP -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_WritePacket(uint8_t *src, uint8_t ch_ep_num, uint16_t bytes) -{ - USB_OTG_Status status = USB_OTG_OK; - uint32_t dword_count = 0 , i = 0; - __IO uint32_t *fifo; - - /* Find the DWORD length, padded by extra bytes as neccessary if MPS - * is not a multiple of DWORD */ - dword_count = (bytes + 3) / 4; - - fifo = core_regs.data_fifo[ch_ep_num]; - - for (i = 0; i < dword_count; i++, src += 4) - { - WRITE_REG32( fifo, *((__packed uint32_t *)src) ); - } - - return status; -} -/******************************************************************************* -* Function Name : OTGD_FS_ReadPacket -* Description : Reads a packet from the Rx FIFO -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -void* OTGD_FS_ReadPacket(uint8_t *dest, uint16_t bytes) -{ - uint32_t i = 0; - uint32_t word_count = (bytes + 3) / 4; - - __IO uint32_t *fifo = core_regs.data_fifo[0]; - uint32_t *data_buff = (uint32_t *)dest; - - for (i = 0; i < word_count; i++, data_buff++) - { - *data_buff = READ_REG32(fifo); - } - - /* Return the buffer pointer because if the transfer is composed of several packets, - the data of the next packet must be stored following the previous packet's data */ - return ((void *)data_buff); -} -/******************************************************************************* -* Function Name : EnableCommonInt -* Description : initializes the commmon interrupts, used in both device and - host modes -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -static void EnableCommonInt(void) -{ - - USB_OTG_int_msk_data int_mask; - - int_mask.d32 = 0; - - /* Clear any pending USB_OTG Interrupts */ - WRITE_REG32( &core_regs.common_regs->otg_int, 0xFFFFFFFF); - - /* Clear any pending common interrupts */ - WRITE_REG32( &core_regs.common_regs->int_sts, 0xFFFFFFFF); - - WRITE_REG32( &core_regs.common_regs->int_msk, int_mask.d32); -} -/******************************************************************************* -* Function Name : OTGD_FS_SetAddress -* Description : Initialize core registers addresses. -* Input : BaseAddress -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_SetAddress(uint32_t BaseAddress) -{ - uint32_t i = 0; - USB_OTG_Status status = USB_OTG_OK; - core_regs.common_regs = (USB_OTG_common_regs *)(BaseAddress + USB_OTG_CORE_GLOBAL_REGS_OFFSET); - core_regs.dev_regs = (USB_OTG_dev_regs *) (BaseAddress + USB_OTG_DEV_GLOBAL_REG_OFFSET); - - for (i = 0; i < MAX_EPS_CHANNELS; i++) - { - core_regs.inep_regs[i] = (USB_OTG_dev_in_ep_regs *) (BaseAddress + USB_OTG_DEV_IN_EP_REG_OFFSET + (i * USB_OTG_EP_REG_OFFSET)); - core_regs.outep_regs[i] = (USB_OTG_dev_out_ep_regs *) (BaseAddress + USB_OTG_DEV_OUT_EP_REG_OFFSET + (i * USB_OTG_EP_REG_OFFSET)); - } - - core_regs.host_regs = (USB_OTG_host_regs *)(BaseAddress + USB_OTG_HOST_GLOBAL_REG_OFFSET); - core_regs.hprt0 = (uint32_t *)(BaseAddress + USB_OTG_HOST_PORT_REGS_OFFSET); - - for (i = 0; i < MAX_EPS_CHANNELS; i++) - { - core_regs.hc_regs[i] = (USB_OTG_hc_regs *)(BaseAddress + USB_OTG_HOST_CHAN_REGS_OFFSET + (i * USB_OTG_CHAN_REGS_OFFSET)); - } - - - for (i = 0; i < MAX_EPS_CHANNELS; i++) - { - core_regs.data_fifo[i] = (uint32_t *)(BaseAddress + USB_OTG_DATA_FIFO_OFFSET + (i * USB_OTG_DATA_FIFO_SIZE)); - } - - core_regs.pcgcctl = (uint32_t *)(BaseAddress + USB_OTG_PCGCCTL_OFFSET); - - return status; -} -/******************************************************************************* -* Function Name : OTGD_FS_CoreInit -* Description : Initialize the USB_OTG controller registers and prepares the core - for device mode or host mode operation. -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_CoreInit(void) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_usb_cfg_data usbcfg; - - usbcfg.d32 = 0; - - /* Reset the Controller */ - OTGD_FS_CoreReset(); - - usbcfg.d32 = READ_REG32(&core_regs.common_regs->usb_cfg); - usbcfg.b.physel = 1; - WRITE_REG32 (&core_regs.common_regs->usb_cfg, usbcfg.d32); - - /* init and configure the phy */ - OTGD_FS_PhyInit(); - - /* Reset after a PHY select and set Host mode */ - OTGD_FS_CoreReset(); - - /* Set Host or Device Mode */ - SetID(); - - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_CoreReset -* Description : Soft reset of the core -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -static USB_OTG_Status OTGD_FS_CoreReset(void) -{ - USB_OTG_Status status = USB_OTG_OK; - __IO USB_OTG_rst_ctl_data greset; - uint32_t count = 0; - - greset.d32 = 0; - - /* Wait for AHB master IDLE state. */ - do - { - uDELAY(3); - greset.d32 = READ_REG32(&core_regs.common_regs->rst_ctl); - if (++count > 200000) - { - return USB_OTG_OK; - } - } - while (greset.b.ahbidle == 0); - - /* Core Soft Reset */ - count = 0; - greset.b.csftrst = 1; - WRITE_REG32(&core_regs.common_regs->rst_ctl, greset.d32 ); - - do - { - greset.d32 = READ_REG32(&core_regs.common_regs->rst_ctl); - if (++count > 200000) - { - break; - } - } - while (greset.b.csftrst == 1); - - /* Wait for 3 PHY Clocks*/ - uDELAY(10); - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_EnableGlobalInt -* Description : Enables the controller's Global Int in the AHB Config reg -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EnableGlobalInt(void) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_ahb_cfg_data ahb_cfg; - - ahb_cfg.d32 = 0; - - ahb_cfg.b.glblintrmsk = 1; /* Enable interrupts */ - MODIFY_REG32(&core_regs.common_regs->ahb_cfg, 0, ahb_cfg.d32); - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_DisableGlobalInt -* Description : Disables the controller's Global Int in the AHB Config reg -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_DisableGlobalInt(void) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_ahb_cfg_data ahbcfg; - - ahbcfg.d32 = 0; - ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ - MODIFY_REG32(&core_regs.common_regs->ahb_cfg, ahbcfg.d32, 0); - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_FlushTxFifo -* Description : Flush a Tx FIFO -* Input : FIFO num -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_FlushTxFifo (uint32_t num ) -{ - - USB_OTG_Status status = USB_OTG_OK; - __IO USB_OTG_rst_ctl_data greset; - uint32_t count = 0; - - greset.d32 = 0; - - greset.b.txfflsh = 1; - greset.b.txfnum = num; - WRITE_REG32( &core_regs.common_regs->rst_ctl, greset.d32 ); - - do - { - greset.d32 = READ_REG32( &core_regs.common_regs->rst_ctl); - if (++count > 200000) - { - break; - } - } - while (greset.b.txfflsh == 1); - - /* Wait for 3 PHY Clocks*/ - uDELAY(3); - - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_FlushRxFifo -* Description : Flush a Rx FIFO -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_FlushRxFifo( void ) -{ - USB_OTG_Status status = USB_OTG_OK; - __IO USB_OTG_rst_ctl_data greset; - uint32_t count = 0; - - greset.d32 = 0; - - greset.b.rxfflsh = 1; - WRITE_REG32( &core_regs.common_regs->rst_ctl, greset.d32 ); - - do - { - greset.d32 = READ_REG32( &core_regs.common_regs->rst_ctl); - if (++count > 200000) - { - break; - } - } - while (greset.b.rxfflsh == 1); - - /* Wait for 3 PHY Clocks*/ - uDELAY(3); - - return status; -} - -/******************************************************************************* -* Function Name : SetID -* Description : Set ID line -* Input : None -* Output : None -* Return : num_in_ep -*******************************************************************************/ -USB_OTG_Status SetID(void) -{ - - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_usb_cfg_data usbcfg ; - - usbcfg.d32 = 0; - - usbcfg.d32 = READ_REG32(&core_regs.common_regs->usb_cfg); - - usbcfg.b.force_dev = 1; - - WRITE_REG32(&core_regs.common_regs->usb_cfg, usbcfg.d32); - - mDELAY(50); - - return status; -} - -/******************************************************************************* -* Function Name : GetMode -* Description : Get current mode -* Input : None -* Output : None -* Return : current mode -*******************************************************************************/ -static uint32_t GetMode(void) -{ - return (READ_REG32(&core_regs.common_regs->int_sts ) & 0x1); -} - -/******************************************************************************* -* Function Name : IsDeviceMode -* Description : Check if it is device mode -* Input : None -* Output : None -* Return : num_in_ep -*******************************************************************************/ -uint8_t IsDeviceMode(void) -{ - return (GetMode() != HOST_MODE); -} - -/******************************************************************************* -* Function Name : IsHostMode -* Description : Check if it is host mode -* Input : None -* Output : None -* Return : num_in_ep -*******************************************************************************/ -uint8_t IsHostMode(void) -{ - return (GetMode() == HOST_MODE); -} - -/******************************************************************************* -* Function Name : OTGD_FS_ReadCoreItr -* Description : returns the Core Interrupt register -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -uint32_t OTGD_FS_ReadCoreItr(void) -{ - uint32_t v = 0; - - v = READ_REG32(&core_regs.common_regs->int_sts); - v &= READ_REG32(&core_regs.common_regs->int_msk); - - return v; -} - -/******************************************************************************* -* Function Name : OTGD_FS_ReadOtgItr -* Description : returns the USB_OTG Interrupt register -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -uint32_t OTGD_FS_ReadOtgItr (void) -{ - return (READ_REG32 (&core_regs.common_regs->otg_int)); -} - -/******************************************************************************/ -/* PCD Core Layer */ -/******************************************************************************/ - -/******************************************************************************* -* Function Name : InitDevSpeed -* Description : Initializes the DevSpd field of the DCFG register depending - on the PHY type and the enumeration speed of the device. -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -static void InitDevSpeed(void) -{ - USB_OTG_dev_cfg_data dcfg; - - dcfg.d32 = 0; - - dcfg.d32 = READ_REG32(&core_regs.dev_regs->dev_cfg); - dcfg.b.devspd = 0x3; /* Full speed PHY */ - WRITE_REG32(&core_regs.dev_regs->dev_cfg, dcfg.d32); -} -/******************************************************************************* -* Function Name : OTGD_FS_CoreInitDev -* Description : Initialize the USB_OTG controller registers for device mode -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_CoreInitDev (void) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_dev_ep_ctl_data depctl; - USB_OTG_dev_cfg_data dcfg; - USB_OTG_fifo_size_data nptxfifosize; - USB_OTG_fifo_size_data txfifosize; - USB_OTG_dev_in_ep_msk_data msk; - uint32_t i = 0; - - depctl.d32 = 0; - dcfg.d32 = 0; - nptxfifosize.d32 = 0; - txfifosize.d32 = 0; - msk.d32 = 0; - - /* Set device speed */ - InitDevSpeed (); - - /* Restart the Phy Clock */ - WRITE_REG32(core_regs.pcgcctl, 0); - - /* Device configuration register */ - dcfg.d32 = READ_REG32( &core_regs.dev_regs->dev_cfg); - dcfg.b.perfrint = DCFG_FRAME_INTERVAL_80; - WRITE_REG32( &core_regs.dev_regs->dev_cfg, dcfg.d32 ); - - /* set Rx FIFO size */ - WRITE_REG32( &core_regs.common_regs->rx_fifo_siz, RX_FIFO_SIZE); - - /* EP0 TX*/ - nptxfifosize.b.depth = TX0_FIFO_SIZE; - nptxfifosize.b.startaddr = RX_FIFO_SIZE; - WRITE_REG32( &core_regs.common_regs->np_tx_fifo_siz, nptxfifosize.d32 ); - - - /* EP1 TX*/ - txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; - txfifosize.b.depth = TX1_FIFO_SIZE; - WRITE_REG32( &core_regs.common_regs->dev_p_tx_fsiz_dieptxf[0], txfifosize.d32 ); - - - /* EP2 TX*/ - txfifosize.b.startaddr += txfifosize.b.depth; - txfifosize.b.depth = TX2_FIFO_SIZE; - WRITE_REG32( &core_regs.common_regs->dev_p_tx_fsiz_dieptxf[1], txfifosize.d32 ); - - - /* EP3 TX*/ - txfifosize.b.startaddr += txfifosize.b.depth; - txfifosize.b.depth = TX3_FIFO_SIZE; - WRITE_REG32( &core_regs.common_regs->dev_p_tx_fsiz_dieptxf[2], txfifosize.d32 ); - - - /* Flush the FIFOs */ - OTGD_FS_FlushTxFifo(0x10); /* all Tx FIFOs */ - OTGD_FS_FlushRxFifo(); - - /* Clear all pending Device Interrupts */ - WRITE_REG32( &core_regs.dev_regs->dev_in_ep_msk, 0 ); - WRITE_REG32( &core_regs.dev_regs->dev_out_ep_msk, 0 ); - WRITE_REG32( &core_regs.dev_regs->dev_all_int, 0xFFFFFFFF ); - WRITE_REG32( &core_regs.dev_regs->dev_all_int_msk, 0 ); - - for (i = 0; i <= MAX_TX_FIFOS; i++) - { - depctl.d32 = READ_REG32(&core_regs.inep_regs[i]->dev_in_ep_ctl); - if (depctl.b.epena) - { - depctl.d32 = 0; - depctl.b.epdis = 1; - depctl.b.snak = 1; - } - else - { - depctl.d32 = 0; - } - - WRITE_REG32( &core_regs.inep_regs[i]->dev_in_ep_ctl, depctl.d32); - - - WRITE_REG32( &core_regs.inep_regs[i]->dev_in_ep_txfer_siz, 0); - WRITE_REG32( &core_regs.inep_regs[i]->dev_in_ep_int, 0xFF); - } - - for (i = 0; i < 1/* NUM_OUT_EPS*/; i++) - { - depctl.d32 = READ_REG32(&core_regs.outep_regs[i]->dev_out_ep_ctl); - if (depctl.b.epena) - { - depctl.d32 = 0; - depctl.b.epdis = 1; - depctl.b.snak = 1; - } - else - { - depctl.d32 = 0; - } - - WRITE_REG32( &core_regs.outep_regs[i]->dev_out_ep_ctl, depctl.d32); - - WRITE_REG32( &core_regs.outep_regs[i]->dev_out_ep_txfer_siz, 0); - WRITE_REG32( &core_regs.outep_regs[i]->dev_out_ep_int, 0xFF); - } - - msk.d32 = 0; - msk.b.txfifoundrn = 1; - MODIFY_REG32(&core_regs.dev_regs->dev_in_ep_msk, msk.d32, msk.d32); - - OTGD_FS_EnableDevInt(); - - return status; -} -/******************************************************************************* -* Function Name : OTGD_FS_EnableDevInt -* Description : Enables the Device mode interrupts -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EnableDevInt(void) -{ - - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_int_msk_data intr_mask; - - intr_mask.d32 = 0; - - /* Disable all interrupts. */ - WRITE_REG32( &core_regs.common_regs->int_msk, 0); - - /* Clear any pending interrupts */ - WRITE_REG32( &core_regs.common_regs->int_sts, 0xFFFFFFFF); - - /* Enable the common interrupts */ - EnableCommonInt(); - - /* Enable the defined interrupts*/ -#ifdef INTR_MODEMISMATCH - intr_mask.b.modemismatch = 1; -#endif /* INTR_MODEMISMATCH */ -#ifdef INTR_SOFINTR - intr_mask.b.sofintr = 1; -#endif /* INTR_SOFINTR */ -#ifdef INTR_RXSTSQLVL - intr_mask.b.rxstsqlvl = 1; -#endif /* INTR_RXSTSQLVL */ -#ifdef INTR_NPTXFEMPTY - intr_mask.b.nptxfempty = 1; -#endif /* INTR_NPTXFEMPTY */ -#ifdef INTR_GINNAKEFF - intr_mask.b.ginnakeff = 1; -#endif /* INTR_GINNAKEFF */ -#ifdef INTR_GOUTNAKEFF - intr_mask.b.goutnakeff = 1; -#endif /* INTR_GOUTNAKEFF */ -#ifdef INTR_ERLYSUSPEND - intr_mask.b.erlysuspend = 1; -#endif /* INTR_ERLYSUSPEND */ -#ifdef INTR_USBSUSPEND - intr_mask.b.usbsuspend = 1; -#endif /* INTR_USBSUSPEND */ -#ifdef INTR_USBRESET - intr_mask.b.usbreset = 1; -#endif /* INTR_USBRESET */ -#ifdef INTR_ENUMDONE - intr_mask.b.enumdone = 1; -#endif /* INTR_ENUMDONE */ -#ifdef INTR_ISOOUTDROP - intr_mask.b.isooutdrop = 1; -#endif /* INTR_ISOOUTDROP */ -#ifdef INTR_EOPFRAME - intr_mask.b.eopframe = 1; -#endif /* INTR_EOPFRAME */ -#ifdef INTR_EPMISMATCH - intr_mask.b.epmismatch = 1; -#endif /* INTR_EPMISMATCH */ -#ifdef INTR_INEPINTR - intr_mask.b.inepintr = 1; -#endif /* INTR_INEPINTR */ -#ifdef INTR_OUTEPINTR - intr_mask.b.outepintr = 1; -#endif /* INTR_OUTEPINTR */ -#ifdef INTR_INCOMPLISOIN - intr_mask.b.incomplisoin = 1; -#endif /* INTR_INCOMPLISOIN */ -#ifdef INTR_INCOMPLISOOUT - intr_mask.b.incomplisoout = 1; -#endif /* INTR_INCOMPLISOOUT */ -#ifdef INTR_DISCONNECT - intr_mask.b.disconnect = 1; -#endif /* INTR_DISCONNECT */ -#ifdef INTR_WKUPINTR - intr_mask.b.wkupintr = 1; -#endif /* INTR_WKUPINTR */ - - MODIFY_REG32( &core_regs.common_regs->int_msk, intr_mask.d32, intr_mask.d32); - return status; - -} -/******************************************************************************* -* Function Name : OTGD_FS_EP0Activate -* Description : enables EP0 OUT to receive SETUP packets and configures EP0 - IN for transmitting packets -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EP0Activate(void) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_dev_sts_data dsts; - USB_OTG_dev_ep_ctl_data diepctl; - USB_OTG_dev_ctl_data dctl; - - dsts.d32 = 0; - diepctl.d32 = 0; - dctl.d32 = 0; - - /* Read the Device Status and Endpoint 0 Control registers */ - dsts.d32 = READ_REG32(&core_regs.dev_regs->dev_sts); - diepctl.d32 = READ_REG32(&core_regs.inep_regs[0]->dev_in_ep_ctl); - - /* Set the MPS of the IN EP based on the enumeration speed */ - switch (dsts.b.enumspd) - { - case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: - case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: - case DSTS_ENUMSPD_FS_PHY_48MHZ: - diepctl.b.mps = DEP0CTL_MPS_64; - break; - case DSTS_ENUMSPD_LS_PHY_6MHZ: - diepctl.b.mps = DEP0CTL_MPS_8; - break; - } - - WRITE_REG32(&core_regs.inep_regs[0]->dev_in_ep_ctl, diepctl.d32); - dctl.b.cgnpinnak = 1; - MODIFY_REG32(&core_regs.dev_regs->dev_ctl, dctl.d32, dctl.d32); - - return status; -} -/******************************************************************************* -* Function Name : OTGD_FS_EPActivate -* Description : Activates an EP -* Input : ep -* Output : None -* Return : num_in_ep -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EPActivate(USB_OTG_EP *ep) -{ - - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_dev_ep_ctl_data depctl; - __IO uint32_t *addr; - USB_OTG_dev_all_int_data daintmsk; - - depctl.d32 = 0; - daintmsk.d32 = 0; - - /* Read DEPCTLn register */ - if (ep->is_in == 1) - { - addr = &core_regs.inep_regs[ep->num]->dev_in_ep_ctl; - daintmsk.ep.in = 1 << ep->num; - } - else - { - addr = &core_regs.outep_regs[ep->num]->dev_out_ep_ctl; - daintmsk.ep.out = 1 << ep->num; - } - - /* If the EP is already active don't change the EP Control - * register. */ - depctl.d32 = READ_REG32(addr); - if (!depctl.b.usbactep) - { - depctl.b.mps = ep->maxpacket; - depctl.b.eptype = ep->type; - depctl.b.txfnum = ep->tx_fifo_num; - depctl.b.setd0pid = 1; - depctl.b.usbactep = 1; - WRITE_REG32(addr, depctl.d32); - } - - /* Enable the Interrupt for this EP */ - MODIFY_REG32(&core_regs.dev_regs->dev_all_int_msk, 0, daintmsk.d32); - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_EPDeactivate -* Description : Deactivates an EP -* Input : ep -* Output : None -* Return : num_in_ep -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EPDeactivate(USB_OTG_EP *ep) -{ - - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_dev_ep_ctl_data depctl; - __IO uint32_t *addr; - USB_OTG_dev_all_int_data daintmsk; - - depctl.d32 = 0; - daintmsk.d32 = 0; - - /* Read DEPCTLn register */ - if (ep->is_in == 1) - { - addr = &core_regs.inep_regs[ep->num]->dev_in_ep_ctl; - daintmsk.ep.in = 1 << ep->num; - } - else - { - addr = &core_regs.outep_regs[ep->num]->dev_out_ep_ctl; - daintmsk.ep.out = 1 << ep->num; - } - - depctl.b.usbactep = 0; - WRITE_REG32(addr, depctl.d32); - - /* Disable the Interrupt for this EP */ - MODIFY_REG32(&core_regs.dev_regs->dev_all_int_msk, daintmsk.d32, 0); - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_EPStartXfer -* Description : Handle the setup for data xfer for an EP and starts the xfer -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EPStartXfer(USB_OTG_EP *ep) -{ - - USB_OTG_Status status = USB_OTG_OK; - __IO USB_OTG_dev_ep_ctl_data depctl; - USB_OTG_dev_ep_txfer_siz_data deptsiz; - - depctl.d32 = 0; - deptsiz.d32 = 0; - - /* IN endpoint */ - if (ep->is_in == 1) - { - - depctl.d32 = READ_REG32(&(core_regs.inep_regs[ep->num]->dev_in_ep_ctl)); - deptsiz.d32 = READ_REG32(&(core_regs.inep_regs[ep->num]->dev_in_ep_txfer_siz)); - - /* Zero Length Packet? */ - if (ep->xfer_len == 0) - { - deptsiz.b.xfersize = 0; - deptsiz.b.pktcnt = 1; - - } - else - { - /* Program the transfer size and packet count - * as follows: xfersize = N * maxpacket + - * short_packet pktcnt = N + (short_packet - * exist ? 1 : 0) - */ - deptsiz.b.xfersize = ep->xfer_len; - deptsiz.b.pktcnt = (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; - } - WRITE_REG32(&core_regs.inep_regs[ep->num]->dev_in_ep_txfer_siz, deptsiz.d32); - - if (ep->type != EP_TYPE_ISOC) - { - /* Enable the Tx FIFO Empty Interrupt for this EP */ - uint32_t fifoemptymsk = 0; - fifoemptymsk = 1 << ep->num; - MODIFY_REG32(&core_regs.dev_regs->dev_fifo_empty_msk, 0, fifoemptymsk); - } - - /* EP enable, IN data in FIFO */ - depctl.b.cnak = 1; - depctl.b.epena = 1; - WRITE_REG32(&core_regs.inep_regs[ep->num]->dev_in_ep_ctl, depctl.d32); - - depctl.d32 = READ_REG32 (&core_regs.inep_regs[0]->dev_in_ep_ctl); - depctl.b.nextep = ep->num; - WRITE_REG32 (&core_regs.inep_regs[0]->dev_in_ep_ctl, depctl.d32); - } - else - { - /* OUT endpoint */ - depctl.d32 = READ_REG32(&(core_regs.outep_regs[ep->num]->dev_out_ep_ctl)); - deptsiz.d32 = READ_REG32(&(core_regs.outep_regs[ep->num]->dev_out_ep_txfer_siz)); - - /* Program the transfer size and packet count as follows: - * pktcnt = N - * xfersize = N * maxpacket - */ - if (ep->xfer_len == 0) - { - deptsiz.b.xfersize = ep->maxpacket; - deptsiz.b.pktcnt = 1; - } - else - { - deptsiz.b.pktcnt = (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; - deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; - } - WRITE_REG32(&core_regs.outep_regs[ep->num]->dev_out_ep_txfer_siz, deptsiz.d32); - - if (ep->type == EP_TYPE_ISOC) - { - - if (ep->even_odd_frame) - { - depctl.b.setd1pid = 1; - } - else - { - depctl.b.setd0pid = 1; - } - } - - /* EP enable */ - depctl.b.cnak = 1; - depctl.b.epena = 1; - - WRITE_REG32(&core_regs.outep_regs[ep->num]->dev_out_ep_ctl, depctl.d32); - - } - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_EP0StartXfer -* Description : Handle the setup for a data xfer for EP0 and starts the xfer -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EP0StartXfer(USB_OTG_EP *ep) -{ - - USB_OTG_Status status = USB_OTG_OK; - uint32_t fifoemptymsk = 0; - USB_OTG_dev_ep_ctl_data depctl; - USB_OTG_dev_ep_txfer_size0_data deptsiz; - USB_OTG_dev_in_ep_regs *in_regs ; - - depctl.d32 = 0; - deptsiz.d32 = 0; - - /* IN endpoint */ - if (ep->is_in == 1) - { - in_regs = core_regs.inep_regs[0]; - depctl.d32 = READ_REG32(&in_regs->dev_in_ep_ctl); - deptsiz.d32 = READ_REG32(&in_regs->dev_in_ep_txfer_siz); - - /* Zero Length Packet? */ - if (ep->xfer_len == 0) - { - deptsiz.b.xfersize = 0; - deptsiz.b.pktcnt = 1; - } - else - { - if (ep->xfer_len > ep->maxpacket) - { - ep->xfer_len = ep->maxpacket; - deptsiz.b.xfersize = ep->maxpacket; - } - else - { - deptsiz.b.xfersize = ep->xfer_len; - } - deptsiz.b.pktcnt = 1; - - } - WRITE_REG32(&in_regs->dev_in_ep_txfer_siz, deptsiz.d32); - - /* EP enable, IN data in FIFO */ - depctl.b.cnak = 1; - depctl.b.epena = 1; - WRITE_REG32(&in_regs->dev_in_ep_ctl, depctl.d32); - - /* Enable the Tx FIFO Empty Interrupt for this EP */ - if (ep->xfer_len > 0) - { - fifoemptymsk |= 1 << ep->num; - MODIFY_REG32(&core_regs.dev_regs->dev_fifo_empty_msk, 0, fifoemptymsk); - } - } - else - { - /* OUT endpoint */ - depctl.d32 = READ_REG32(&core_regs.outep_regs[ep->num]->dev_out_ep_ctl); - deptsiz.d32 = READ_REG32(&core_regs.outep_regs[ep->num]->dev_out_ep_txfer_siz); - - /* Program the transfer size and packet count as follows: - * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) - * pktcnt = N */ - if (ep->xfer_len == 0) - { - deptsiz.b.xfersize = ep->maxpacket; - deptsiz.b.pktcnt = 1; - } - else - { - deptsiz.b.pktcnt = (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; - deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; - } - - WRITE_REG32(&core_regs.outep_regs[ep->num]->dev_out_ep_txfer_siz, deptsiz.d32); - - /* EP enable */ - depctl.b.cnak = 1; - depctl.b.epena = 1; - WRITE_REG32 (&(core_regs.outep_regs[ep->num]->dev_out_ep_ctl), depctl.d32); - } - return status; -} -/******************************************************************************* -* Function Name : OTGD_FS_EPSetStall -* Description : Set the EP STALL -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EPSetStall(USB_OTG_EP *ep) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_dev_ep_ctl_data depctl; - __IO uint32_t *depctl_addr; - - depctl.d32 = 0; - - - if (ep->is_in == 1) - { - depctl_addr = &(core_regs.inep_regs[ep->num]->dev_in_ep_ctl); - depctl.d32 = READ_REG32(depctl_addr); - - /* set the disable and stall bits */ - if (depctl.b.epena) - { - depctl.b.epdis = 1; - } - depctl.b.stall = 1; - WRITE_REG32(depctl_addr, depctl.d32); - } - else - { - depctl_addr = &(core_regs.outep_regs[ep->num]->dev_out_ep_ctl); - depctl.d32 = READ_REG32(depctl_addr); - - /* set the stall bit */ - depctl.b.stall = 1; - WRITE_REG32(depctl_addr, depctl.d32); - } - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_EPClearStall -* Description : Clear the EP STALL -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -USB_OTG_Status OTGD_FS_EPClearStall(USB_OTG_EP *ep) -{ - USB_OTG_Status status = USB_OTG_OK; - USB_OTG_dev_ep_ctl_data depctl; - __IO uint32_t *depctl_addr; - - - depctl.d32 = 0; - - if (ep->is_in == 1) - { - depctl_addr = &(core_regs.inep_regs[ep->num]->dev_in_ep_ctl); - } - else - { - depctl_addr = &(core_regs.outep_regs[ep->num]->dev_out_ep_ctl); - } - - - depctl.d32 = READ_REG32(depctl_addr); - - /* clear the stall bits */ - depctl.b.stall = 0; - - if (ep->type == EP_TYPE_INTR || ep->type == EP_TYPE_BULK) - { - depctl.b.setd0pid = 1; /* DATA0 */ - } - - WRITE_REG32(depctl_addr, depctl.d32); - return status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_ReadDevAllOutEp_itr -* Description : returns the OUT endpoint interrupt bits -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -uint32_t OTGD_FS_ReadDevAllOutEp_itr(void) -{ - uint32_t v = 0; - - v = READ_REG32(&core_regs.dev_regs->dev_all_int); - v &= READ_REG32(&core_regs.dev_regs->dev_all_int_msk); - return ((v & 0xffff0000) >> 16); -} - -/******************************************************************************* -* Function Name : OTGD_FS_ReadDevOutEP_itr -* Description : returns the Device OUT EP Interrupt register -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -uint32_t OTGD_FS_ReadDevOutEP_itr(USB_OTG_EP *ep) -{ - uint32_t v = 0; - - v = READ_REG32(&core_regs.outep_regs[ep->num]->dev_out_ep_int); - v &= READ_REG32(&core_regs.dev_regs->dev_out_ep_msk); - return v; -} -/******************************************************************************* -* Function Name : OTGD_FS_ReadDevAllInEPItr -* Description : Get int status register -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -uint32_t OTGD_FS_ReadDevAllInEPItr(void) -{ - uint32_t v = 0; - - v = READ_REG32(&core_regs.dev_regs->dev_all_int); - v &= READ_REG32(&core_regs.dev_regs->dev_all_int_msk); - return (v & 0xffff); -} - -/******************************************************************************* -* Function Name : OTGD_FS_Dev_GetEPStatus -* Description : returns the EP Status -* Input : - ep: pointer to the EP structure -* Output : None -* Return : status: DEV_EP_TX_STALL, DEV_EP_TX_VALID, DEV_EP_TX_NAK, -* DEV_EP_RX_STALL, DEV_EP_RX_VALID or DEV_EP_RX_NAK, -*******************************************************************************/ -uint32_t OTGD_FS_Dev_GetEPStatus(USB_OTG_EP *ep) -{ - USB_OTG_dev_ep_ctl_data depctl; - __IO uint32_t *depctl_addr; - uint32_t Status = 0; - - depctl.d32 = 0; - - if (ep->is_in == 1) - { - depctl_addr = &(core_regs.inep_regs[ep->num]->dev_in_ep_ctl); - } - else - { - depctl_addr = &(core_regs.outep_regs[ep->num]->dev_out_ep_ctl); - } - - depctl.d32 = READ_REG32(depctl_addr); - - /* Process for IN endpoint */ - if (ep->is_in == 1) - { - if (depctl.b.stall == 1) - Status = DEV_EP_TX_STALL; - else if (depctl.b.naksts == 1) - Status = DEV_EP_TX_NAK; - else - Status = DEV_EP_TX_VALID; - } - /* Process for OUT endpoint */ - else - { - if (depctl.b.stall == 1) - Status = DEV_EP_RX_STALL; - else if (depctl.b.naksts == 1) - Status = DEV_EP_RX_NAK; - else - Status = DEV_EP_RX_VALID; - } - - /* Return the current status */ - return Status; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Dev_SetEPStatus -* Description : Sets the EP Status -* Input : - ep: pointer to the EP structure -* - Status: new status to be set -* Output : None -* Return : None -*******************************************************************************/ -void OTGD_FS_Dev_SetEPStatus(USB_OTG_EP *ep, uint32_t Status) -{ - USB_OTG_dev_ep_ctl_data depctl; - __IO uint32_t *depctl_addr; - - depctl.d32 = 0; - - - if (ep->is_in == 1) - { - depctl_addr = &(core_regs.inep_regs[ep->num]->dev_in_ep_ctl); - } - else - { - depctl_addr = &(core_regs.outep_regs[ep->num]->dev_out_ep_ctl); - } - - depctl.d32 = READ_REG32(depctl_addr); - - /* Process for IN endpoint */ - if (ep->is_in == 1) - { - if (Status == DEV_EP_TX_STALL) - { - OTGD_FS_EPSetStall(ep); return; - } - else if (Status == DEV_EP_TX_NAK) - depctl.b.snak = 1; - else if (Status == DEV_EP_TX_VALID) - { - if (depctl.b.stall == 1) - { - ep->even_odd_frame = 0; - OTGD_FS_EPClearStall(ep); - return; - } - depctl.b.cnak = 1; - depctl.b.usbactep = 1; - depctl.b.epena = 1; - } - else if (Status == DEV_EP_TX_DIS) - depctl.b.usbactep = 0; - } - else /* Process for OUT endpoint */ - { - if (Status == DEV_EP_RX_STALL) - depctl.b.stall = 1; - else if (Status == DEV_EP_RX_NAK) - depctl.b.snak = 1; - else if (Status == DEV_EP_RX_VALID) - { - if (depctl.b.stall == 1) - { - ep->even_odd_frame = 0; - OTGD_FS_EPClearStall(ep); - return; - } - depctl.b.cnak = 1; - depctl.b.usbactep = 1; - depctl.b.epena = 1; - } - else if (Status == DEV_EP_RX_DIS) - { - depctl.b.usbactep = 0; - } - } - - if (ep->type == EP_TYPE_INTR || ep->type == EP_TYPE_BULK) - { - depctl.b.setd0pid = 1; /* DATA0 */ - } - - WRITE_REG32(depctl_addr, depctl.d32); -} - -/******************************************************************************* -* Function Name : OTGD_FS_Dev_SetRemoteWakeup -* Description : Enable Remote wakeup signaling -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -void OTGD_FS_Dev_SetRemoteWakeup() -{ - USB_OTG_dev_ctl_data devctl; - __IO uint32_t *dctl_addr; - - devctl.d32 = 0; - - dctl_addr = &(core_regs.dev_regs->dev_ctl); - - devctl.d32 = READ_REG32( dctl_addr); - - /* Enable the Remote Wakeup signal */ - devctl.b.rmtwkupsig = 1; - - WRITE_REG32(dctl_addr, devctl.d32); -} - -/******************************************************************************* -* Function Name : OTGD_FS_Dev_ResetRemoteWakeup -* Description : Disable Remote wakeup signaling -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -void OTGD_FS_Dev_ResetRemoteWakeup() -{ - USB_OTG_dev_ctl_data devctl; - __IO uint32_t *dctl_addr; - - - devctl.d32 = 0; - - dctl_addr = &(core_regs.dev_regs->dev_ctl); - - devctl.d32 = READ_REG32( dctl_addr); - - /* Disable the Remote Wakeup signal */ - devctl.b.rmtwkupsig = 0; - - - WRITE_REG32(dctl_addr, devctl.d32); -} -#endif /* STM32F10X_CL */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/otgd_fs_dev.c b/STM32_USB-FS-Device_Driver/src/otgd_fs_dev.c deleted file mode 100644 index 9b518e8..0000000 --- a/STM32_USB-FS-Device_Driver/src/otgd_fs_dev.c +++ /dev/null @@ -1,386 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_dev.c -* Author : STMicroelectronics -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : High Layer device mode interface and wrapping layer. -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -#ifdef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "otgd_fs_dev.h" -#include "usb_regs.h" -#include "otgd_fs_cal.h" -#include "otgd_fs_pcd.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ - -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : OTG_DEV_Init -* Description : Initialize the OTG Device IP and EP0. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void OTG_DEV_Init(void) -{ - EP_DESCRIPTOR ep_descriptor; - USB_OTG_EP *ep; - - /* Set the OTG_USB base registers address */ - OTGD_FS_SetAddress(USB_OTG_FS1_BASE_ADDR); - - /* Disable all global interrupts */ - OTGD_FS_DisableGlobalInt(); - - /*Init the Core (common init.) */ - OTGD_FS_CoreInit(); - - /* Init Device */ - OTGD_FS_CoreInitDev(); - - /* Init internal driver structure */ - OTGD_FS_PCD_Init(); - - /* Configure and open the IN control EP0 */ - ep_descriptor.bEndpointAddress = 0x80; - ep_descriptor.wMaxPacketSize = 64; - ep_descriptor.bmAttributes = USB_ENDPOINT_XFER_CONTROL; - OTGD_FS_PCD_EP_Open(&ep_descriptor); - - /* Configure and open the OUT control EP0 */ - ep_descriptor.bEndpointAddress = 0x00; - OTGD_FS_PCD_EP_Open(&ep_descriptor); - - - ep = OTGD_FS_PCD_GetOutEP(0); - OTGD_FS_EPStartXfer(ep); - - /* Enable EP0 to start receiving setup packets */ - OTGD_FS_PCD_EP0_OutStart(); - - /* Enable USB Global interrupt */ - OTGD_FS_EnableGlobalInt(); -} - - -/******************************************************************************* -* Function Name : OTG_DEV_EP_Init -* Description : Initialize the selected endpoint parameters -* Input : - bEpAdd: address of the endpoint (epnum|epdir) -* expample: EP1 OUT -> 0x01 and EP1 IN 0x81. -* - bEpType: OTG_DEV_EP_TYPE_CONTROL, OTG_DEV_EP_TYPE_ISOC, -* OTG_DEV_EP_TYPE_BULK, OTG_DEV_EP_TYPE_INT -* - wEpMaxPackSize: The EP max packet size. -* Output : None. -* Return : Status: New status to be set for the endpoint: -*******************************************************************************/ -void OTG_DEV_EP_Init(uint8_t bEpAdd, uint8_t bEpType, uint16_t wEpMaxPackSize) -{ - EP_DESCRIPTOR ep_descriptor; - USB_OTG_EP *ep; - - /* Set the EP parameters in a structure */ - ep_descriptor.bEndpointAddress = bEpAdd; - ep_descriptor.bmAttributes = bEpType; - ep_descriptor.wMaxPacketSize = wEpMaxPackSize; - - OTGD_FS_PCD_EP_Flush(bEpAdd); - - /* Open the EP with entered parameters */ - OTGD_FS_PCD_EP_Open(&ep_descriptor); - - /* Activate the EP if it is an OUT EP */ - if ((bEpAdd & 0x80) == 0) - { - ep = OTGD_FS_PCD_GetOutEP(bEpAdd & 0x7F); - OTGD_FS_EPStartXfer(ep); - } - else - { - ep = OTGD_FS_PCD_GetInEP(bEpAdd & 0x7F); - ep->even_odd_frame = 0; - OTG_DEV_SetEPTxStatus(bEpAdd, DEV_EP_TX_NAK); - } - -} - -/******************************************************************************* -* Function Name : OTG_DEV_GetEPTxStatus -* Description : Set the related endpoint status. -* Input : Number of the endpoint. -* Output : None. -* Return : Status: New status to be set for the endpoint: -*******************************************************************************/ -uint32_t OTG_DEV_GetEPTxStatus(uint8_t bEpnum) -{ - USB_OTG_EP *ep; - uint32_t status = 0; - - ep = OTGD_FS_PCD_GetInEP(bEpnum & 0x7F); - - status = OTGD_FS_Dev_GetEPStatus(ep); - - return status; -} - -/******************************************************************************* -* Function Name : OTG_DEV_GetEPRxStatus -* Description : returns the related endpoint status. -* Input : Number of the endpoint. -* Output : None. -* Return : Status: New status to be set for the endpoint: -*******************************************************************************/ -uint32_t OTG_DEV_GetEPRxStatus(uint8_t bEpnum) -{ - USB_OTG_EP *ep; - uint32_t status = 0; - - ep = OTGD_FS_PCD_GetOutEP(bEpnum & 0x7F); - - status = OTGD_FS_Dev_GetEPStatus(ep); - - return status; -} - -/******************************************************************************* -* Function Name : OTG_DEV_SetEPTxStatus -* Description : Sets the related endpoint status. -* Input : - bEpnum: Number of the endpoint. -* - Status: New status to be set for the endpoint. It can be -* DEV_EP_TX_VALID, DEV_EP_TX_STALL, DEV_EP_TX_NAK or -* DEV_EP_TX_DISABLE. -* Output : None. -* Return : None. -*******************************************************************************/ -void OTG_DEV_SetEPTxStatus(uint8_t bEpnum, uint32_t Status) -{ - USB_OTG_EP *ep; - - ep = OTGD_FS_PCD_GetInEP(bEpnum & 0x7F); - - if ((bEpnum == 0x80) && (Status == DEV_EP_TX_STALL)) - { - ep->is_in = 1; - } - - OTGD_FS_Dev_SetEPStatus(ep, Status); -} - -/******************************************************************************* -* Function Name : OTG_DEV_SetEPRxStatus -* Description : Sets the related endpoint status. -* Input : - bEpnum: Number of the endpoint. -* - Status: New status to be set for the endpoint. It can be -* DEV_EP_RX_VALID, DEV_EP_RX_STALL, DEV_EP_RX_NAK or -* DEV_EP_RX_DISABLE. -* Output : None. -* Return : None. -*******************************************************************************/ -void OTG_DEV_SetEPRxStatus(uint8_t bEpnum, uint32_t Status) -{ - USB_OTG_EP *ep; - - ep = OTGD_FS_PCD_GetOutEP(bEpnum & 0x7F); - - OTGD_FS_Dev_SetEPStatus(ep, Status); -} - -/******************************************************************************* -* Function Name : USB_DevDisconnect -* Description : Disconnect the Pullup resist. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void USB_DevDisconnect(void) -{ - OTGD_FS_PCD_DevDisconnect(); -} - -/******************************************************************************* -* Function Name : USB_DevConnect -* Description : Disconnect the . -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void USB_DevConnect(void) -{ - OTGD_FS_PCD_DevConnect(); -} - -/*-*-*-*-*-*-*-*-*-* Replace the usb_regs.h defines -*-*-*-*-*-*-*-*-*-*-*-*-*/ - -/******************************************************************************* -* Function Name : SetEPTxStatus -* Description : Set the status of Tx endpoint. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxStatus(uint8_t bEpNum, uint16_t wState) -{ - _SetEPTxStatus(bEpNum, wState); -} - -/******************************************************************************* -* Function Name : SetEPRxStatus -* Description : Set the status of Rx endpoint. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxStatus(uint8_t bEpNum, uint16_t wState) -{ - _SetEPRxStatus(bEpNum, wState); -} - -/******************************************************************************* -* Function Name : GetEPTxStatus -* Description : Returns the endpoint Tx status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint TX Status -*******************************************************************************/ -uint16_t GetEPTxStatus(uint8_t bEpNum) -{ - return(_GetEPTxStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : GetEPRxStatus -* Description : Returns the endpoint Rx status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint RX Status -*******************************************************************************/ -uint16_t GetEPRxStatus(uint8_t bEpNum) -{ - return(_GetEPRxStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPTxValid -* Description : Valid the endpoint Tx Status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxValid(uint8_t bEpNum) -{ - _SetEPTxStatus(bEpNum, EP_TX_VALID); -} - -/******************************************************************************* -* Function Name : SetEPRxValid -* Description : Valid the endpoint Rx Status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxValid(uint8_t bEpNum) -{ - _SetEPRxStatus(bEpNum, EP_RX_VALID); -} - -/******************************************************************************* -* Function Name : GetTxStallStatus -* Description : Returns the Stall status of the Tx endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Tx Stall status. -*******************************************************************************/ -uint16_t GetTxStallStatus(uint8_t bEpNum) -{ - return(_GetTxStallStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : GetRxStallStatus -* Description : Returns the Stall status of the Rx endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx Stall status. -*******************************************************************************/ -uint16_t GetRxStallStatus(uint8_t bEpNum) -{ - return(_GetRxStallStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPTxCount. -* Description : Set the Tx count. -* Input : bEpNum: Endpoint Number. -* wCount: new count value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxCount(uint8_t bEpNum, uint16_t wCount) -{ -} - -/******************************************************************************* -* Function Name : SetEPRxCount -* Description : Set the Rx count. -* Input : bEpNum: Endpoint Number. -* wCount: the new count value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxCount(uint8_t bEpNum, uint16_t wCount) -{ -} - -/******************************************************************************* -* Function Name : ToWord -* Description : merge two byte in a word. -* Input : bh: byte high, bl: bytes low. -* Output : None. -* Return : resulted word. -*******************************************************************************/ -uint16_t ToWord(uint8_t bh, uint8_t bl) -{ - uint16_t wRet = 0; - wRet = (uint16_t)bl | ((uint16_t)bh << 8); - return(wRet); -} - -/******************************************************************************* -* Function Name : ByteSwap -* Description : Swap two byte in a word. -* Input : wSwW: word to Swap. -* Output : None. -* Return : resulted word. -*******************************************************************************/ -uint16_t ByteSwap(uint16_t wSwW) -{ - uint8_t bTemp = 0; - uint16_t wRet = 0; - - bTemp = (uint8_t)(wSwW & 0xff); - wRet = (wSwW >> 8) | ((uint16_t)bTemp << 8); - return(wRet); -} - -#endif /* STM32F10X_CL */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/otgd_fs_int.c b/STM32_USB-FS-Device_Driver/src/otgd_fs_int.c deleted file mode 100644 index 6120a4e..0000000 --- a/STM32_USB-FS-Device_Driver/src/otgd_fs_int.c +++ /dev/null @@ -1,874 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_int.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Endpoint interrupt's service routines. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -#ifdef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x.h" -#include "usb_type.h" -#include "otgd_fs_int.h" -#include "usb_lib.h" -#include "usb_istr.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Max size of the received OUT Non periodic packet */ -#define MAX_OUT_PKT_SIZE 160 - -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ - -uint8_t USBD_Data_Buffer [MAX_OUT_PKT_SIZE]; -__IO uint8_t IsocBuff [(ISOC_BUFFER_SZE * NUM_SUB_BUFFERS)]; -__IO uint32_t IsocBufferIdx = 0; - -extern USB_OTG_CORE_REGS core_regs; - -__IO uint16_t SaveRState; -__IO uint16_t SaveTState; - -/* Extern variables ----------------------------------------------------------*/ -extern void (*pEpInt_IN[7])(void); /* Handles IN interrupts */ -extern void (*pEpInt_OUT[7])(void); /* Handles OUT interrupts */ - -/* Private function prototypes -----------------------------------------------*/ -static uint32_t OTGD_FS_PCD_ReadDevInEP( USB_OTG_EP *ep); -static enum usb_device_speed OTGD_FS_PCD_GetDeviceSpeed(void); -static uint32_t OTGD_FS_PCD_WriteEmptyTxFifo(uint32_t epnum); - -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_ModeMismatch_ISR -* Description : Handles the Mode Mismatch error interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_ModeMismatch_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - gintsts.d32 = 0 ; - - INTR_MODEMISMATCH_Callback(); - - /* Clear interrupt */ - gintsts.b.modemismatch = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_Sof_ISR -* Description : Handles the Start Of Frame detected interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_Sof_ISR(void) -{ - USB_OTG_int_sts_data int_sts ; - int_sts.d32 = 0; - - /* Call user function */ - INTR_SOFINTR_Callback(); - - /* Clear interrupt */ - int_sts.b.sofintr = 1; - WRITE_REG32 (&core_regs.common_regs->int_sts, int_sts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_RxStatusQueueLevel_ISR -* Description : Handles the Rx Status Queue Level Interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_RxStatusQueueLevel_ISR(void) -{ - USB_OTG_int_msk_data int_mask; - USB_OTG_dev_rx_sts_data status; - USB_OTG_EP *ep; - - int_mask.d32 = 0; - status.d32 = 0; - - /* Disable the Rx Status Queue Level interrupt */ - int_mask.b.rxstsqlvl = 1; - MODIFY_REG32( &core_regs.common_regs->int_msk, int_mask.d32, 0); - - /* Get the Status from the top of the FIFO */ - status.d32 = READ_REG32( &core_regs.common_regs->rx_stsp ); - - /* Get the related endpoint structure */ - ep = OTGD_FS_PCD_GetOutEP(status.b.epnum); - - switch (status.b.pktsts) - { - case STS_GOUT_NAK: - break; - case STS_DATA_UPDT: - if (status.b.bcnt) - { - if (ep->type == EP_TYPE_ISOC) - { - /* Call user function */ - INTR_RXSTSQLVL_ISODU_Callback(); - - /* Copy the received buffer to the RAM */ - OTGD_FS_ReadPacket((uint8_t*)(IsocBuff + (ISOC_BUFFER_SZE * IsocBufferIdx)), status.b.bcnt); - ep->xfer_buff = (uint8_t*)(IsocBuff + (ISOC_BUFFER_SZE * IsocBufferIdx)); - - /* Check if the end of the global buffer has been reached */ - if (IsocBufferIdx == (NUM_SUB_BUFFERS - 1)) - { - /* Reset the buffer index */ - IsocBufferIdx = 0; - } - else - { - /* Increment the buffer index */ - IsocBufferIdx ++; - } - } - else - { - /* Copy the received buffer to the RAM */ - OTGD_FS_ReadPacket(USBD_Data_Buffer, status.b.bcnt); - ep->xfer_buff = USBD_Data_Buffer; - } - - /* Update the endpoint structure */ - ep->xfer_len = status.b.bcnt; - ep->xfer_count += status.b.bcnt; - } - break; - case STS_XFER_COMP: - break; - case STS_SETUP_COMP: - break; - case STS_SETUP_UPDT: - /* Copy the setup packet received in Fifo into the setup buffer in RAM */ - OTGD_FS_ReadPacket(USBD_Data_Buffer, 8); - ep->xfer_buff = USBD_Data_Buffer; - ep->xfer_count += status.b.bcnt; - ep->xfer_len = status.b.bcnt; - break; - default: - break; - } - - /* Call the user function */ - INTR_RXSTSQLVL_Callback(); - - /* Enable the Rx Status Queue Level interrupt */ - MODIFY_REG32( &core_regs.common_regs->int_msk, 0, int_mask.d32); - - /* Clear interrupt: this is a read only bit, it cannot be cleared by register - access */ - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_NPTxFE_ISR -* Description : Handles the Non Periodic Tx FIFO Empty interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_NPTxFE_ISR(void ) -{ - USB_OTG_int_msk_data gintmsk; - gintmsk.d32 = 0; - - /* Call the user function */ - INTR_NPTXFEMPTY_Callback(); - - gintmsk.b.nptxfempty = 1; - MODIFY_REG32(&core_regs.common_regs->int_msk, gintmsk.d32, 0 ); - - /* Clear interrupt: This bit is a read only bit, cannot be cleared - by register access */ - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_GInNakEff_ISR -* Description : Handles the Global IN Endpoints NAK Effective interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_GInNakEff_ISR(void) -{ - - /* Call user function */ - INTR_GINNAKEFF_Callback(); - - /* Clear interrupt: This is a read only bit, it cannot be cleared by register - access */ - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_GOutNakEff_ISR -* Description : Handles the Global OUT Endpoints NAK Effective interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_GOutNakEff_ISR(void) -{ - /* Call user function */ - INTR_GOUTNAKEFF_Callback(); - - /* Clear interrupt: This is a read only bit, it cannot be cleared by register - access */ - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_EarlySuspend_ISR -* Description : Handles the Early Suspend detected interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_EarlySuspend_ISR(void ) -{ - USB_OTG_int_sts_data gintsts; - USB_OTG_int_msk_data gintmsk; - - gintsts.d32 = 0; - gintmsk.d32 = 0; - - - /* Call user function */ - INTR_ERLYSUSPEND_Callback(); - - gintmsk.b.erlysuspend = 1; - MODIFY_REG32(&core_regs.common_regs->int_msk, gintmsk.d32, 0 ); - - /* Clear interrupt */ - gintsts.b.erlysuspend = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_USBSuspend_ISR -* Description : Handles the Suspend condition detected interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_USBSuspend_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - - gintsts.d32 = 0; - /* Call user function */ - INTR_USBSUSPEND_Callback(); - - /* Clear interrupt */ - gintsts.b.usbsuspend = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_UsbReset_ISR -* Description : This interrupt occurs when a USB Reset is detected. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_UsbReset_ISR(void) -{ - USB_OTG_dev_all_int_data daintmsk; - USB_OTG_dev_out_ep_msk_data doepmsk; - USB_OTG_dev_in_ep_msk_data diepmsk; - USB_OTG_dev_cfg_data dcfg; - USB_OTG_dev_ctl_data dctl; - USB_OTG_int_sts_data gintsts; - - daintmsk.d32 = 0; - doepmsk.d32 = 0; - diepmsk.d32 = 0; - dcfg.d32 =0; - dctl.d32 = 0; - gintsts.d32 = 0; - - /* Clear the Remote Wakeup Signalling */ - dctl.b.rmtwkupsig = 1; - MODIFY_REG32(&core_regs.dev_regs->dev_ctl, dctl.d32, 0 ); - - /* Flush the NP Tx FIFO */ - OTGD_FS_FlushTxFifo( 0 ); - - daintmsk.b.inep0 = 1; - daintmsk.b.outep0 = 1; - WRITE_REG32( &core_regs.dev_regs->dev_all_int_msk, daintmsk.d32 ); - - doepmsk.b.setup = 1; - doepmsk.b.xfercompl = 1; - doepmsk.b.ahberr = 1; - doepmsk.b.epdisabled = 1; - WRITE_REG32( &core_regs.dev_regs->dev_out_ep_msk, doepmsk.d32 ); - - diepmsk.b.xfercompl = 1; - diepmsk.b.timeout = 1; - diepmsk.b.epdisabled = 1; - diepmsk.b.ahberr = 1; - diepmsk.b.intknepmis = 1; - WRITE_REG32( &core_regs.dev_regs->dev_in_ep_msk, diepmsk.d32 ); - - /* Reset Device Address */ - dcfg.d32 = READ_REG32( &core_regs.dev_regs->dev_cfg); - dcfg.b.devaddr = 0; - WRITE_REG32( &core_regs.dev_regs->dev_cfg, dcfg.d32); - - /* setup EP0 to receive SETUP packets */ - OTGD_FS_PCD_EP0_OutStart(); - - /* Clear interrupt */ - gintsts.d32 = 0; - gintsts.b.usbreset = 1; - WRITE_REG32 (&core_regs.common_regs->int_sts, gintsts.d32); - - /* Call the user reset function */ - OTGD_FS_DEVICE_RESET; - - /* Call user function */ - INTR_USBRESET_Callback(); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_EnumDone_ISR -* Description : Reads the device status register and set the device speed -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_EnumDone_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - USB_OTG_usb_cfg_data gusbcfg; - - gintsts.d32 = 0; - gusbcfg.d32 = 0; - - OTGD_FS_EP0Activate(); - - /* Set USB turnaround time based on device speed and PHY interface. */ - gusbcfg.d32 = READ_REG32(&core_regs.common_regs->usb_cfg); - - /* Full or low speed */ - if ( OTGD_FS_PCD_GetDeviceSpeed() == USB_SPEED_FULL) - { - gusbcfg.b.usbtrdtim = 9; - } - WRITE_REG32(&core_regs.common_regs->usb_cfg, gusbcfg.d32); - - /* Call user function */ - INTR_ENUMDONE_Callback(); - - /* Clear interrupt */ - gintsts.b.enumdone = 1; - WRITE_REG32( &core_regs.common_regs->int_sts, gintsts.d32 ); - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_IsoOutDrop_ISR -* Description : Handles the Isochrounous Out packet Dropped interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_IsoOutDrop_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - - gintsts.d32 = 0; - /* Call user function */ - INTR_ISOOUTDROP_Callback(); - - /* Clear interrupt */ - gintsts.b.isooutdrop = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_EOPF_ISR -* Description : Handles the Expexted End Of Periodic Frame interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_EOPF_ISR(void ) -{ - USB_OTG_int_sts_data gintsts; - USB_OTG_int_msk_data gintmsk; - - gintsts.d32 = 0; - gintmsk.d32 = 0; - - gintmsk.b.eopframe = 1; - MODIFY_REG32(&core_regs.common_regs->int_msk, gintmsk.d32, 0 ); - - /* Call user function */ - INTR_EOPFRAME_Callback(); - - /* Clear interrupt */ - gintsts.b.eopframe = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_EPMismatch_ISR -* Description : Handles the Endpoint Mismatch error interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_EPMismatch_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - - gintsts.d32 = 0; - - /* Call user function */ - INTR_EPMISMATCH_Callback(); - - /* Clear interrupt */ - gintsts.b.epmismatch = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_InEP_ISR -* Description : Handles all IN endpoints interrupts. -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_InEP_ISR(void) -{ - USB_OTG_dev_in_ep_int_data diepint; - - uint32_t ep_intr = 0; - uint32_t epnum = 0; - USB_OTG_EP *ep; - uint32_t fifoemptymsk = 0; - - diepint.d32 = 0; - ep_intr = OTGD_FS_ReadDevAllInEPItr(); - while ( ep_intr ) - { - if (ep_intr&0x1) /* In ITR */ - { - ep = OTGD_FS_PCD_GetInEP(epnum); - diepint.d32 = OTGD_FS_PCD_ReadDevInEP(ep); /* Get In ITR status */ - if ( diepint.b.xfercompl ) - { - fifoemptymsk = 0x1 << ep->num; - MODIFY_REG32(&core_regs.dev_regs->dev_fifo_empty_msk, fifoemptymsk, 0); - - /* Clear the Interrupt flag */ - CLEAR_IN_EP_INTR(epnum, xfercompl); - - if (epnum == 0) - { - /* Call the core IN process for EP0 */ - In0_Process(); - - /* before terminate set Tx & Rx status */ - OTG_DEV_SetEPRxStatus(epnum, SaveRState); - OTG_DEV_SetEPTxStatus(epnum, SaveTState); - } - else - { - OTG_DEV_SetEPTxStatus((epnum | 0x80 ), DEV_EP_TX_NAK); - - (*pEpInt_IN[epnum -1])(); - - /* Toggle Endpoint frame ID */ - if (ep->even_odd_frame == 0) - ep->even_odd_frame = 1; - else - ep->even_odd_frame = 0; - } - } - if ( diepint.b.ahberr ) - { - CLEAR_IN_EP_INTR(epnum, ahberr); - } - if ( diepint.b.timeout ) - { - CLEAR_IN_EP_INTR(epnum, timeout); - } - if (diepint.b.intktxfemp) - { - CLEAR_IN_EP_INTR(epnum, intktxfemp); - } - if (diepint.b.intknepmis) - { - CLEAR_IN_EP_INTR(epnum, intknepmis); - } - if (diepint.b.inepnakeff) - { - CLEAR_IN_EP_INTR(epnum, inepnakeff); - } - if (diepint.b.emptyintr) - { - if ((epnum == 0) || (OTG_DEV_GetEPTxStatus(epnum) == DEV_EP_TX_VALID)) - { - OTGD_FS_PCD_WriteEmptyTxFifo(epnum); - } - - CLEAR_IN_EP_INTR(epnum, emptyintr); - } - if ( diepint.b.epdisabled ) - { - /* Reset Endpoint Frame ID to 0 */ - ep->even_odd_frame = 0; - - CLEAR_IN_EP_INTR(epnum, epdisabled); - } - } - epnum++; - ep_intr >>= 1; - } - - /* Call user function */ - INTR_INEPINTR_Callback(); - - return 1; -} - - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_OutEP_ISR -* Description : Handles all OUT endpoints interrupts. -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_OutEP_ISR(void) -{ - uint32_t ep_intr = 0; - USB_OTG_dev_out_ep_int_data doepint; - uint32_t epnum = 0; - USB_OTG_EP *ep; - - doepint.d32 = 0; - - /* Read in the device interrupt bits */ - ep_intr = OTGD_FS_ReadDevAllOutEp_itr(); - - while ( ep_intr ) - { - if (ep_intr&0x1) - { - /* Get EP pointer */ - ep = OTGD_FS_PCD_GetOutEP(epnum); - doepint.d32 = OTGD_FS_ReadDevOutEP_itr(ep); - - /* Transfer complete */ - if ( doepint.b.xfercompl ) - { - /* Clear the bit in DOEPINTn for this interrupt */ - CLEAR_OUT_EP_INTR(epnum, xfercompl); - - if (epnum == 0) - { - /* Call the OUT process for the EP0 */ - Out0_Process(); - } - else - { - (*pEpInt_OUT[epnum-1])(); - } - } - /* Endpoint disable */ - if ( doepint.b.epdisabled ) - { - /* Clear the bit in DOEPINTn for this interrupt */ - CLEAR_OUT_EP_INTR(epnum, epdisabled); - } - /* AHB Error */ - if ( doepint.b.ahberr ) - { - CLEAR_OUT_EP_INTR(epnum, ahberr); - } - /* Setup Phase Done (control EPs) */ - if ( doepint.b.setup ) - { - if (epnum == 0) - { - /* Call the SETUP process for the EP0 */ - Setup0_Process(); - - /* Before exit, update the Tx status */ - OTG_DEV_SetEPTxStatus(0x80, SaveTState); - } - else - { - /* Other control endpoints */ - } - - /* Clear the EP Interrupt */ - CLEAR_OUT_EP_INTR(epnum, setup); - } - } - epnum++; - ep_intr >>= 1; - } - - /* Call user function */ - INTR_OUTEPINTR_Callback(); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_IncomplIsoIn_ISR -* Description : Handles the Incomplete Isochrous IN tranfer error interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_IncomplIsoIn_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - - gintsts.d32 = 0; - - /* Call user function */ - INTR_INCOMPLISOIN_Callback(); - - /* Clear interrupt */ - gintsts.b.incomplisoin = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_IncomplIsoOut_ISR -* Description : Handles the Incomplete Isochrous OUT tranfer error interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_IncomplIsoOut_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - - gintsts.d32 = 0; - - /* Call user function */ - INTR_INCOMPLISOOUT_Callback(); - - /* Clear interrupt */ - gintsts.b.outepintr = 1; - WRITE_REG32(&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_Handle_Wakeup_ISR -* Description : Handles the Wakeup or Remote Wakeup detected interrupt. -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_Handle_Wakeup_ISR(void) -{ - USB_OTG_int_sts_data gintsts; - - gintsts.d32 = 0; - /* Call user function */ - INTR_WKUPINTR_Callback(); - - /* Clear interrupt */ - gintsts.b.wkupintr = 1; - WRITE_REG32 (&core_regs.common_regs->int_sts, gintsts.d32); - - return 1; -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_GetDeviceSpeed -* Description : Get the device speed from the device status register -* Input : None -* Output : None -* Return : The Device speed value. -*******************************************************************************/ -static enum usb_device_speed OTGD_FS_PCD_GetDeviceSpeed(void) -{ - USB_OTG_dev_sts_data dsts; - enum usb_device_speed speed = USB_SPEED_UNKNOWN; - - dsts.d32 = 0; - - dsts.d32 = READ_REG32(&core_regs.dev_regs->dev_sts); - - switch (dsts.b.enumspd) - { - case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: - speed = USB_SPEED_HIGH; - break; - case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: - case DSTS_ENUMSPD_FS_PHY_48MHZ: - speed = USB_SPEED_FULL; - break; - - case DSTS_ENUMSPD_LS_PHY_6MHZ: - speed = USB_SPEED_LOW; - break; - } - - return speed; -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_ReadDevInEP -* Description : Reads all the Endpoints flags. -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -static uint32_t OTGD_FS_PCD_ReadDevInEP( USB_OTG_EP *ep) -{ - uint32_t v = 0, msk = 0, emp=0; - - msk = READ_REG32(&core_regs.dev_regs->dev_in_ep_msk); - emp = READ_REG32(&core_regs.dev_regs->dev_fifo_empty_msk); - msk |= ((emp >> ep->num) & 0x1) << 7; - v = READ_REG32(&core_regs.inep_regs[ep->num]->dev_in_ep_int) & msk; - - return v; -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_WriteEmptyTxFifo -* Description : Checks Fifo for the next packet to be loaded. -* Input : None -* Output : None -* Return : Status -*******************************************************************************/ -static uint32_t OTGD_FS_PCD_WriteEmptyTxFifo(uint32_t epnum) -{ - USB_OTG_dev_tx_fifo_sts_data txstatus; - USB_OTG_EP *ep; - uint32_t len = 0; - uint32_t dwords = 0; - USB_OTG_dev_ep_ctl_data depctl; - - - txstatus.d32 = 0; - depctl.d32 = 0; - - ep = OTGD_FS_PCD_GetInEP(epnum); - - len = ep->xfer_len - ep->xfer_count; - - if (len > ep->maxpacket) - { - len = ep->maxpacket; - } - - dwords = (len + 3) / 4; - txstatus.d32 = READ_REG32( &core_regs.inep_regs[epnum]->dev_tx_fifo_sts); - - /* Manage the case of 0-length data packets toggling data PID */ - if ((ep->xfer_len == 0) && (ep->xfer_count == 0)) - { - if (ep->num > 0) - { - depctl.d32 = READ_REG32( &core_regs.inep_regs[epnum]->dev_in_ep_ctl); - if (ep->even_odd_frame == 1) - { - depctl.b.setd0pid = 0; - depctl.b.setd1pid = 1; - } - else - { - depctl.b.setd0pid = 1; - depctl.b.setd1pid = 0; - } - WRITE_REG32( &core_regs.inep_regs[epnum]->dev_in_ep_ctl, depctl.d32); - } - } - - - while ((txstatus.b.txfspcavail > dwords) && - (ep->xfer_count < ep->xfer_len) && - (ep->xfer_len) != 0) - { - if (ep->num > 0) - { - depctl.d32 = READ_REG32( &core_regs.inep_regs[epnum]->dev_in_ep_ctl); - if (ep->even_odd_frame == 0) - { - depctl.b.setd0pid = 1; - depctl.b.setd1pid = 0; - } - else - { - depctl.b.setd0pid = 0; - depctl.b.setd1pid = 1; - } - WRITE_REG32( &core_regs.inep_regs[epnum]->dev_in_ep_ctl, depctl.d32); - } - - /* Write the FIFO */ - len = ep->xfer_len - ep->xfer_count; - - if (len > ep->maxpacket) - { - len = ep->maxpacket; - } - dwords = (len + 3) / 4; - - OTGD_FS_WritePacket(ep->xfer_buff, epnum, len); - - ep->xfer_count += len; - ep->xfer_buff += len; - - txstatus.d32 = READ_REG32(&core_regs.inep_regs[epnum]->dev_tx_fifo_sts); - } - - return 1; -} -#endif /* STM32F10X_CL */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/otgd_fs_pcd.c b/STM32_USB-FS-Device_Driver/src/otgd_fs_pcd.c deleted file mode 100644 index c838757..0000000 --- a/STM32_USB-FS-Device_Driver/src/otgd_fs_pcd.c +++ /dev/null @@ -1,454 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : otgd_fs_pcd.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Peripheral Device Interface low layer. -******************************************************************************** -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -#ifdef STM32F10X_CL - -#include "usb_lib.h" -#include "otgd_fs_cal.h" -#include "otgd_fs_pcd.h" - -USB_OTG_PCD_DEV USB_OTG_PCD_dev; - -extern USB_OTG_CORE_REGS core_regs; -/******************************************************************************* -* Function Name : OTGD_FS_PCD_Init -* Description : Initialize the USB Device portion of the driver. -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -void OTGD_FS_PCD_Init(void) -{ - uint32_t i = 0; - USB_OTG_EP *ep; - - ep = &USB_OTG_PCD_dev.ep0; - USB_OTG_PCD_dev.ep0state = 0; - - /* Init ep structure */ - ep->num = 0; - ep->tx_fifo_num = 0; - - /* Control until ep is actvated */ - ep->type = EP_TYPE_CTRL; - ep->maxpacket = MAX_PACKET_SIZE; - - ep->xfer_buff = 0; - ep->xfer_len = 0; - - for (i = 1; i < MAX_TX_FIFOS ; i++) - { - ep = &USB_OTG_PCD_dev.in_ep[i-1]; - - /* Init ep structure */ - ep->is_in = 1; - ep->num = i; - ep->tx_fifo_num = i; - - /* Control until ep is actvated */ - ep->type = EP_TYPE_CTRL; - ep->maxpacket = MAX_PACKET_SIZE; - ep->xfer_buff = 0; - ep->xfer_len = 0; - } - - for (i = 1; i < MAX_TX_FIFOS; i++) - { - ep = &USB_OTG_PCD_dev.out_ep[i-1]; - - /* Init ep structure */ - ep->is_in = 0; - ep->num = i; - ep->tx_fifo_num = i; - - /* Control until ep is activated */ - ep->type = EP_TYPE_CTRL; - ep->maxpacket = MAX_PACKET_SIZE; - ep->xfer_buff = 0; - ep->xfer_len = 0; - } - - USB_OTG_PCD_dev.ep0.maxpacket = MAX_EP0_SIZE; - USB_OTG_PCD_dev.ep0.type = EP_TYPE_CTRL; - -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP_Open -* Description : Configure an Endpoint -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_Open(EP_DESCRIPTOR *epdesc) -{ - USB_OTG_EP *ep; - - - if ((0x80 & epdesc->bEndpointAddress) != 0) - { - ep = OTGD_FS_PCD_GetInEP(epdesc->bEndpointAddress & 0x7F); - ep->is_in = 1; - } - else - { - ep = OTGD_FS_PCD_GetOutEP(epdesc->bEndpointAddress & 0x7F); - ep->is_in = 0; - } - - ep->num = epdesc->bEndpointAddress & 0x7F; - ep->maxpacket = epdesc->wMaxPacketSize; - ep->type = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - if (ep->is_in) - { - /* Assign a Tx FIFO */ - ep->tx_fifo_num = ep->num; - } - - /* Set initial data PID. */ - if ((epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK ) - { - ep->data_pid_start = 0; - } - - OTGD_FS_EPActivate(ep ); - - return 0; -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP_Close -* Description : Called when an EP is disabled -* Input : Endpoint address. -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_Close(uint8_t ep_addr) -{ - - USB_OTG_EP *ep; - - if ((0x80 & ep_addr) != 0) - { - ep = OTGD_FS_PCD_GetInEP(ep_addr & 0x7F); - } - else - { - ep = OTGD_FS_PCD_GetOutEP(ep_addr & 0x7F); - } - - ep->num = ep_addr & 0x7F; - ep->is_in = (0x80 & ep_addr) != 0; - - OTGD_FS_EPDeactivate(ep ); - return 0; -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP_Read -* Description : Read data from Fifo -* Input : Endpoint address. -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_Read (uint8_t ep_addr, uint8_t *pbuf, uint32_t buf_len) -{ - USB_OTG_EP *ep; - uint32_t i = 0; - - ep = OTGD_FS_PCD_GetOutEP(ep_addr & 0x7F); - - /* copy received data into application buffer */ - for (i = 0 ; i < buf_len ; i++) - { - pbuf[i] = ep->xfer_buff[i]; - } - - /*setup and start the Xfer */ - ep->xfer_buff = pbuf; - ep->xfer_len = buf_len; - ep->xfer_count = 0; - ep->is_in = 0; - ep->num = ep_addr & 0x7F; - - if ( ep->num == 0 ) - { - OTGD_FS_EP0StartXfer(ep); - } - else if (USB_OTG_PCD_dev.ep0state == 0) - { - OTGD_FS_EPStartXfer( ep ); - } - - return 0; -} - -/******************************************************************************* -* Function Name : USBF_EP_Write -* Description : Read data from Fifo -* Input : ep -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_Write (uint8_t ep_addr, uint8_t *pbuf, uint32_t buf_len) -{ - USB_OTG_EP *ep; - - ep = OTGD_FS_PCD_GetInEP(ep_addr & 0x7f); - - /* assign data to EP structure buffer */ - ep->xfer_buff = pbuf; - - /* Setup and start the Transfer */ - ep->xfer_count = 0; - ep->xfer_len = buf_len; - ep->is_in = 1; - ep->num = ep_addr & 0x7F; - - if ( ep->num == 0 ) - { - OTGD_FS_EP0StartXfer(ep); - } - else if (USB_OTG_PCD_dev.ep0state == 0) - { - OTGD_FS_EPStartXfer( ep ); - } - - return 0; -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP_Stall -* Description : Stall an endpoint. -* Input : Endpoint Address. -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_Stall (uint8_t ep_addr) -{ - USB_OTG_EP *ep; - - if ((0x80 & ep_addr) != 0) - { - ep = OTGD_FS_PCD_GetInEP(ep_addr & 0x7F); - } - else - { - ep = OTGD_FS_PCD_GetOutEP(ep_addr & 0x7F); - } - - ep->num = ep_addr & 0x7F; - ep->is_in = ((ep_addr & 0x80) == 0x80) ? 1 : 0; - - OTGD_FS_EPSetStall(ep); - return (0); -} -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP_ClrStall -* Description : Clear stall condition on endpoints. -* Input : Endpoint Address. -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_ClrStall (uint8_t ep_addr) -{ - - USB_OTG_EP *ep; - - if ((0x80 & ep_addr) != 0) - { - ep = OTGD_FS_PCD_GetInEP(ep_addr & 0x7F); - } - else - { - ep = OTGD_FS_PCD_GetOutEP(ep_addr & 0x7F); - } - - ep->num = ep_addr & 0x7F; - ep->is_in = ((ep_addr & 0x80) == 0x80) ? 1 : 0; - - OTGD_FS_EPClearStall(ep); - - return (0); -} - -/******************************************************************************* -* Function Name : USBF_FCD_EP_Flush() -* Description : This Function flushes the buffer. -* Input : Endpoint Address. -* Output : None -* Return : status -*******************************************************************************/ -uint32_t OTGD_FS_PCD_EP_Flush (uint8_t ep_addr) -{ - - uint8_t is_out = 0; - uint8_t ep_nbr = 0; - - ep_nbr = ep_addr & 0x7F; - is_out = ((ep_addr & 0x80) == 0x80) ? 0 : 1; - - if (is_out == 0) - { - OTGD_FS_FlushTxFifo(ep_nbr); - } - else - { - OTGD_FS_FlushRxFifo(); - } - OTGD_FS_PCD_EP_ClrStall(ep_addr); - return (0); -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP_SetAddress -* Description : This Function set USB device address -* Input : The new device Address to be set. -* Output : None -* Return : status -*******************************************************************************/ -void OTGD_FS_PCD_EP_SetAddress (uint8_t address) -{ - - USB_OTG_dev_cfg_data dcfg; - - dcfg.d32 = 0; - - dcfg.b.devaddr = address; - MODIFY_REG32( &core_regs.dev_regs->dev_cfg, 0, dcfg.d32); -} - - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_GetInEP -* Description : This function returns pointer to IN EP struct with number ep_num -* Input : Endpoint Number. -* Output : None -* Return : status -*******************************************************************************/ -USB_OTG_EP* OTGD_FS_PCD_GetInEP(uint32_t ep_num) -{ - uint32_t i = 0; - - if (ep_num == 0) - { - return &USB_OTG_PCD_dev.ep0; - } - else - { - for (i = 0; i < MAX_TX_FIFOS; ++i) - { - if (USB_OTG_PCD_dev.in_ep[i].num == ep_num) - return &USB_OTG_PCD_dev.in_ep[i]; - } - return 0; - } -} -/******************************************************************************* -* Function Name : USBF_GetOutEP -* Description : returns pointer to OUT EP struct with number ep_num -* Input : Endpoint Number. -* Output : None -* Return : USBF_EP -*******************************************************************************/ -USB_OTG_EP* OTGD_FS_PCD_GetOutEP(uint32_t ep_num) -{ - uint32_t i = 0; - - if (ep_num == 0) - { - return &USB_OTG_PCD_dev.ep0; - } - else - { - for (i = 0; i < MAX_TX_FIFOS; ++i) - { - if (USB_OTG_PCD_dev.out_ep[i].num == ep_num) - return &USB_OTG_PCD_dev.out_ep[i]; - } - return 0; - } -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_DevConnect -* Description : Connect device -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -void OTGD_FS_PCD_DevConnect(void) -{ - - USB_OTG_dev_ctl_data dctl; - - dctl.d32 = 0; - - dctl.d32 = READ_REG32(&core_regs.dev_regs->dev_ctl); - - /* Connect device */ - dctl.b.sftdiscon = 0; - WRITE_REG32(&core_regs.dev_regs->dev_ctl, dctl.d32); - mDELAY(25); -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_DevDisconnect -* Description : Disconnect device -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -void OTGD_FS_PCD_DevDisconnect (void) -{ - - USB_OTG_dev_ctl_data dctl; - - dctl.d32 = 0; - - dctl.d32 = READ_REG32(&core_regs.dev_regs->dev_ctl); - - /* Disconnect device for 20ms */ - dctl.b.sftdiscon = 1; - WRITE_REG32(&core_regs.dev_regs->dev_ctl, dctl.d32); - mDELAY(25); -} - -/******************************************************************************* -* Function Name : OTGD_FS_PCD_EP0_OutStart -* Description : Configures EPO to receive SETUP packets. -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -void OTGD_FS_PCD_EP0_OutStart(void) -{ - - USB_OTG_dev_ep_txfer_size0_data doeptsize0; - doeptsize0.d32 = 0; - - - doeptsize0.b.supcnt = 3; - doeptsize0.b.pktcnt = 1; - doeptsize0.b.xfersize = 8 * 3; - - WRITE_REG32( &core_regs.outep_regs[0]->dev_out_ep_txfer_siz, doeptsize0.d32 ); - -} - -#endif /* STM32F10X_CL */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - diff --git a/STM32_USB-FS-Device_Driver/src/usb_core.c b/STM32_USB-FS-Device_Driver/src/usb_core.c deleted file mode 100644 index 8fc2963..0000000 --- a/STM32_USB-FS-Device_Driver/src/usb_core.c +++ /dev/null @@ -1,1088 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_core.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Standard protocol processing (USB v2.0) -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -#define ValBit(VAR,Place) (VAR & (1 << Place)) -#define SetBit(VAR,Place) (VAR |= (1 << Place)) -#define ClrBit(VAR,Place) (VAR &= ((1 << Place) ^ 255)) - -#ifdef STM32F10X_CL - #define Send0LengthData() {OTGD_FS_PCD_EP_Write (0, 0, 0) ; vSetEPTxStatus(EP_TX_VALID);} -#else -#define Send0LengthData() { _SetEPTxCount(ENDP0, 0); \ - vSetEPTxStatus(EP_TX_VALID); \ - } -#endif /* STM32F10X_CL */ - -#define vSetEPRxStatus(st) (SaveRState = st) -#define vSetEPTxStatus(st) (SaveTState = st) - -#define USB_StatusIn() Send0LengthData() -#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID) - -#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */ -#define StatusInfo1 StatusInfo.bw.bb0 - -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -uint16_t_uint8_t StatusInfo; - -bool Data_Mul_MaxPacketSize = FALSE; -/* Private function prototypes -----------------------------------------------*/ -static void DataStageOut(void); -static void DataStageIn(void); -static void NoData_Setup0(void); -static void Data_Setup0(void); -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : Standard_GetConfiguration. -* Description : Return the current configuration variable address. -* Input : Length - How many bytes are needed. -* Output : None. -* Return : Return 1 , if the request is invalid when "Length" is 0. -* Return "Buffer" if the "Length" is not 0. -*******************************************************************************/ -uint8_t *Standard_GetConfiguration(uint16_t Length) -{ - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = - sizeof(pInformation->Current_Configuration); - return 0; - } - pUser_Standard_Requests->User_GetConfiguration(); - return (uint8_t *)&pInformation->Current_Configuration; -} - -/******************************************************************************* -* Function Name : Standard_SetConfiguration. -* Description : This routine is called to set the configuration value -* Then each class should configure device themself. -* Input : None. -* Output : None. -* Return : Return USB_SUCCESS, if the request is performed. -* Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetConfiguration(void) -{ - - if ((pInformation->USBwValue0 <= - Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0) - && (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/ - { - pInformation->Current_Configuration = pInformation->USBwValue0; - pUser_Standard_Requests->User_SetConfiguration(); - return USB_SUCCESS; - } - else - { - return USB_UNSUPPORT; - } -} - -/******************************************************************************* -* Function Name : Standard_GetInterface. -* Description : Return the Alternate Setting of the current interface. -* Input : Length - How many bytes are needed. -* Output : None. -* Return : Return 0, if the request is invalid when "Length" is 0. -* Return "Buffer" if the "Length" is not 0. -*******************************************************************************/ -uint8_t *Standard_GetInterface(uint16_t Length) -{ - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = - sizeof(pInformation->Current_AlternateSetting); - return 0; - } - pUser_Standard_Requests->User_GetInterface(); - return (uint8_t *)&pInformation->Current_AlternateSetting; -} - -/******************************************************************************* -* Function Name : Standard_SetInterface. -* Description : This routine is called to set the interface. -* Then each class should configure the interface them self. -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetInterface(void) -{ - RESULT Re; - /*Test if the specified Interface and Alternate Setting are supported by - the application Firmware*/ - Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0); - - if (pInformation->Current_Configuration != 0) - { - if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0) - || (pInformation->USBwValue1 != 0)) - { - return USB_UNSUPPORT; - } - else if (Re == USB_SUCCESS) - { - pUser_Standard_Requests->User_SetInterface(); - pInformation->Current_Interface = pInformation->USBwIndex0; - pInformation->Current_AlternateSetting = pInformation->USBwValue0; - return USB_SUCCESS; - } - - } - - return USB_UNSUPPORT; -} - -/******************************************************************************* -* Function Name : Standard_GetStatus. -* Description : Copy the device request data to "StatusInfo buffer". -* Input : - Length - How many bytes are needed. -* Output : None. -* Return : Return 0, if the request is at end of data block, -* or is invalid when "Length" is 0. -*******************************************************************************/ -uint8_t *Standard_GetStatus(uint16_t Length) -{ - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = 2; - return 0; - } - - /* Reset Status Information */ - StatusInfo.w = 0; - - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - /*Get Device Status */ - uint8_t Feature = pInformation->Current_Feature; - - /* Remote Wakeup enabled */ - if (ValBit(Feature, 5)) - { - SetBit(StatusInfo0, 1); - } - else - { - ClrBit(StatusInfo0, 1); - } - - /* Bus-powered */ - if (ValBit(Feature, 6)) - { - SetBit(StatusInfo0, 0); - } - else /* Self-powered */ - { - ClrBit(StatusInfo0, 0); - } - } - /*Interface Status*/ - else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - { - return (uint8_t *)&StatusInfo; - } - /*Get EndPoint Status*/ - else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - { - uint8_t Related_Endpoint; - uint8_t wIndex0 = pInformation->USBwIndex0; - - Related_Endpoint = (wIndex0 & 0x0f); - if (ValBit(wIndex0, 7)) - { - /* IN endpoint */ - if (_GetTxStallStatus(Related_Endpoint)) - { - SetBit(StatusInfo0, 0); /* IN Endpoint stalled */ - } - } - else - { - /* OUT endpoint */ - if (_GetRxStallStatus(Related_Endpoint)) - { - SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */ - } - } - - } - else - { - return NULL; - } - pUser_Standard_Requests->User_GetStatus(); - return (uint8_t *)&StatusInfo; -} - -/******************************************************************************* -* Function Name : Standard_ClearFeature. -* Description : Clear or disable a specific feature. -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_ClearFeature(void) -{ - uint32_t Type_Rec = Type_Recipient; - uint32_t Status; - - - if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - {/*Device Clear Feature*/ - ClrBit(pInformation->Current_Feature, 5); - return USB_SUCCESS; - } - else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - {/*EndPoint Clear Feature*/ - const DEVICE* pDev; - uint32_t Related_Endpoint; - uint32_t wIndex0; - uint32_t rEP; - - if ((pInformation->USBwValue != ENDPOINT_STALL) - || (pInformation->USBwIndex1 != 0)) - { - return USB_UNSUPPORT; - } - - pDev = &Device_Table; - wIndex0 = pInformation->USBwIndex0; - rEP = wIndex0 & ~0x80; - Related_Endpoint = ENDP0 + rEP; - - if (ValBit(pInformation->USBwIndex0, 7)) - { - /*Get Status of endpoint & stall the request if the related_ENdpoint - is Disabled*/ - Status = _GetEPTxStatus(Related_Endpoint); - } - else - { - Status = _GetEPRxStatus(Related_Endpoint); - } - - if ((rEP >= pDev->Total_Endpoint) || (Status == 0) - || (pInformation->Current_Configuration == 0)) - { - return USB_UNSUPPORT; - } - - - if (wIndex0 & 0x80) - { - /* IN endpoint */ - if (_GetTxStallStatus(Related_Endpoint )) - { - #ifndef STM32F10X_CL - ClearDTOG_TX(Related_Endpoint); - #endif /* STM32F10X_CL */ - SetEPTxStatus(Related_Endpoint, EP_TX_VALID); - } - } - else - { - /* OUT endpoint */ - if (_GetRxStallStatus(Related_Endpoint)) - { - if (Related_Endpoint == ENDP0) - { - /* After clear the STALL, enable the default endpoint receiver */ - SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize); - _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); - } - else - { - #ifndef STM32F10X_CL - ClearDTOG_RX(Related_Endpoint); - #endif /* STM32F10X_CL */ - _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); - } - } - } - pUser_Standard_Requests->User_ClearFeature(); - return USB_SUCCESS; - } - - return USB_UNSUPPORT; -} - -/******************************************************************************* -* Function Name : Standard_SetEndPointFeature -* Description : Set or enable a specific feature of EndPoint -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetEndPointFeature(void) -{ - uint32_t wIndex0; - uint32_t Related_Endpoint; - uint32_t rEP; - uint32_t Status; - - wIndex0 = pInformation->USBwIndex0; - rEP = wIndex0 & ~0x80; - Related_Endpoint = ENDP0 + rEP; - - if (ValBit(pInformation->USBwIndex0, 7)) - { - /* get Status of endpoint & stall the request if the related_ENdpoint - is Disabled*/ - Status = _GetEPTxStatus(Related_Endpoint); - } - else - { - Status = _GetEPRxStatus(Related_Endpoint); - } - - if (Related_Endpoint >= Device_Table.Total_Endpoint - || pInformation->USBwValue != 0 || Status == 0 - || pInformation->Current_Configuration == 0) - { - return USB_UNSUPPORT; - } - else - { - if (wIndex0 & 0x80) - { - /* IN endpoint */ - _SetEPTxStatus(Related_Endpoint, EP_TX_STALL); - } - - else - { - /* OUT endpoint */ - _SetEPRxStatus(Related_Endpoint, EP_RX_STALL); - } - } - pUser_Standard_Requests->User_SetEndPointFeature(); - return USB_SUCCESS; -} - -/******************************************************************************* -* Function Name : Standard_SetDeviceFeature. -* Description : Set or enable a specific feature of Device. -* Input : None. -* Output : None. -* Return : - Return USB_SUCCESS, if the request is performed. -* - Return USB_UNSUPPORT, if the request is invalid. -*******************************************************************************/ -RESULT Standard_SetDeviceFeature(void) -{ - SetBit(pInformation->Current_Feature, 5); - pUser_Standard_Requests->User_SetDeviceFeature(); - return USB_SUCCESS; -} - -/******************************************************************************* -* Function Name : Standard_GetDescriptorData. -* Description : Standard_GetDescriptorData is used for descriptors transfer. -* : This routine is used for the descriptors resident in Flash -* or RAM -* pDesc can be in either Flash or RAM -* The purpose of this routine is to have a versatile way to -* response descriptors request. It allows user to generate -* certain descriptors with software or read descriptors from -* external storage part by part. -* Input : - Length - Length of the data in this transfer. -* - pDesc - A pointer points to descriptor struct. -* The structure gives the initial address of the descriptor and -* its original size. -* Output : None. -* Return : Address of a part of the descriptor pointed by the Usb_ -* wOffset The buffer pointed by this address contains at least -* Length bytes. -*******************************************************************************/ -uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc) -{ - uint32_t wOffset; - - wOffset = pInformation->Ctrl_Info.Usb_wOffset; - if (Length == 0) - { - pInformation->Ctrl_Info.Usb_wLength = pDesc->Descriptor_Size - wOffset; - return 0; - } - - return pDesc->Descriptor + wOffset; -} - -/******************************************************************************* -* Function Name : DataStageOut. -* Description : Data stage of a Control Write Transfer. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void DataStageOut(void) -{ - ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; - uint32_t save_rLength; - - save_rLength = pEPinfo->Usb_rLength; - - if (pEPinfo->CopyData && save_rLength) - { - uint8_t *Buffer; - uint32_t Length; - - Length = pEPinfo->PacketSize; - if (Length > save_rLength) - { - Length = save_rLength; - } - - Buffer = (*pEPinfo->CopyData)(Length); - pEPinfo->Usb_rLength -= Length; - pEPinfo->Usb_rOffset += Length; - - #ifdef STM32F10X_CL - OTGD_FS_PCD_EP_Read(ENDP0, Buffer, Length); - #else - PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length); - #endif /* STM32F10X_CL */ - } - - if (pEPinfo->Usb_rLength != 0) - { - vSetEPRxStatus(EP_RX_VALID);/* re-enable for next data reception */ - SetEPTxCount(ENDP0, 0); - vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */ - } - /* Set the next State*/ - if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize) - { - pInformation->ControlState = OUT_DATA; - } - else - { - if (pEPinfo->Usb_rLength > 0) - { - pInformation->ControlState = LAST_OUT_DATA; - } - else if (pEPinfo->Usb_rLength == 0) - { - pInformation->ControlState = WAIT_STATUS_IN; - USB_StatusIn(); - } - } -} - -/******************************************************************************* -* Function Name : DataStageIn. -* Description : Data stage of a Control Read Transfer. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void DataStageIn(void) -{ - ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; - uint32_t save_wLength = pEPinfo->Usb_wLength; - uint32_t ControlState = pInformation->ControlState; - - uint8_t *DataBuffer; - uint32_t Length; - - if ((save_wLength == 0) && (ControlState == LAST_IN_DATA)) - { - if(Data_Mul_MaxPacketSize == TRUE) - { - /* No more data to send and empty packet */ - Send0LengthData(); - ControlState = LAST_IN_DATA; - Data_Mul_MaxPacketSize = FALSE; - } - else - { - /* No more data to send so STALL the TX Status*/ - ControlState = WAIT_STATUS_OUT; - - #ifdef STM32F10X_CL - OTGD_FS_PCD_EP_Read (ENDP0, 0, 0); - #endif /* STM32F10X_CL */ - - #ifndef STM32F10X_CL - vSetEPTxStatus(EP_TX_STALL); - #endif /* STM32F10X_CL */ - } - - goto Expect_Status_Out; - } - - Length = pEPinfo->PacketSize; - ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA; - - if (Length > save_wLength) - { - Length = save_wLength; - } - - DataBuffer = (*pEPinfo->CopyData)(Length); - -#ifdef STM32F10X_CL - OTGD_FS_PCD_EP_Write (ENDP0, DataBuffer, Length); -#else - UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length); -#endif /* STM32F10X_CL */ - - SetEPTxCount(ENDP0, Length); - - pEPinfo->Usb_wLength -= Length; - pEPinfo->Usb_wOffset += Length; - vSetEPTxStatus(EP_TX_VALID); - - USB_StatusOut();/* Expect the host to abort the data IN stage */ - -Expect_Status_Out: - pInformation->ControlState = ControlState; -} - -/******************************************************************************* -* Function Name : NoData_Setup0. -* Description : Proceed the processing of setup request without data stage. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void NoData_Setup0(void) -{ - RESULT Result = USB_UNSUPPORT; - uint32_t RequestNo = pInformation->USBbRequest; - uint32_t ControlState; - - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - /* Device Request*/ - /* SET_CONFIGURATION*/ - if (RequestNo == SET_CONFIGURATION) - { - Result = Standard_SetConfiguration(); - } - - /*SET ADDRESS*/ - else if (RequestNo == SET_ADDRESS) - { - if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0) - || (pInformation->USBwIndex != 0) - || (pInformation->Current_Configuration != 0)) - /* Device Address should be 127 or less*/ - { - ControlState = STALLED; - goto exit_NoData_Setup0; - } - else - { - Result = USB_SUCCESS; - - #ifdef STM32F10X_CL - SetDeviceAddress(pInformation->USBwValue0); - #endif /* STM32F10X_CL */ - } - } - /*SET FEATURE for Device*/ - else if (RequestNo == SET_FEATURE) - { - if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP) - && (pInformation->USBwIndex == 0) - && (ValBit(pInformation->Current_Feature, 5))) - { - Result = Standard_SetDeviceFeature(); - } - else - { - Result = USB_UNSUPPORT; - } - } - /*Clear FEATURE for Device */ - else if (RequestNo == CLEAR_FEATURE) - { - if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP - && pInformation->USBwIndex == 0 - && ValBit(pInformation->Current_Feature, 5)) - { - Result = Standard_ClearFeature(); - } - else - { - Result = USB_UNSUPPORT; - } - } - - } - - /* Interface Request*/ - else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - { - /*SET INTERFACE*/ - if (RequestNo == SET_INTERFACE) - { - Result = Standard_SetInterface(); - } - } - - /* EndPoint Request*/ - else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - { - /*CLEAR FEATURE for EndPoint*/ - if (RequestNo == CLEAR_FEATURE) - { - Result = Standard_ClearFeature(); - } - /* SET FEATURE for EndPoint*/ - else if (RequestNo == SET_FEATURE) - { - Result = Standard_SetEndPointFeature(); - } - } - else - { - Result = USB_UNSUPPORT; - } - - - if (Result != USB_SUCCESS) - { - Result = (*pProperty->Class_NoData_Setup)(RequestNo); - if (Result == USB_NOT_READY) - { - ControlState = PAUSE; - goto exit_NoData_Setup0; - } - } - - if (Result != USB_SUCCESS) - { - ControlState = STALLED; - goto exit_NoData_Setup0; - } - - ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */ - - USB_StatusIn(); - -exit_NoData_Setup0: - pInformation->ControlState = ControlState; - return; -} - -/******************************************************************************* -* Function Name : Data_Setup0. -* Description : Proceed the processing of setup request with data stage. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Data_Setup0(void) -{ - uint8_t *(*CopyRoutine)(uint16_t); - RESULT Result; - uint32_t Request_No = pInformation->USBbRequest; - - uint32_t Related_Endpoint, Reserved; - uint32_t wOffset, Status; - - - - CopyRoutine = NULL; - wOffset = 0; - - /*GET DESCRIPTOR*/ - if (Request_No == GET_DESCRIPTOR) - { - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - uint8_t wValue1 = pInformation->USBwValue1; - if (wValue1 == DEVICE_DESCRIPTOR) - { - CopyRoutine = pProperty->GetDeviceDescriptor; - } - else if (wValue1 == CONFIG_DESCRIPTOR) - { - CopyRoutine = pProperty->GetConfigDescriptor; - } - else if (wValue1 == STRING_DESCRIPTOR) - { - CopyRoutine = pProperty->GetStringDescriptor; - } /* End of GET_DESCRIPTOR */ - } - } - - /*GET STATUS*/ - else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0) - && (pInformation->USBwLength == 0x0002) - && (pInformation->USBwIndex1 == 0)) - { - /* GET STATUS for Device*/ - if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - && (pInformation->USBwIndex == 0)) - { - CopyRoutine = Standard_GetStatus; - } - - /* GET STATUS for Interface*/ - else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - { - if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS) - && (pInformation->Current_Configuration != 0)) - { - CopyRoutine = Standard_GetStatus; - } - } - - /* GET STATUS for EndPoint*/ - else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) - { - Related_Endpoint = (pInformation->USBwIndex0 & 0x0f); - Reserved = pInformation->USBwIndex0 & 0x70; - - if (ValBit(pInformation->USBwIndex0, 7)) - { - /*Get Status of endpoint & stall the request if the related_ENdpoint - is Disabled*/ - Status = _GetEPTxStatus(Related_Endpoint); - } - else - { - Status = _GetEPRxStatus(Related_Endpoint); - } - - if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0) - && (Status != 0)) - { - CopyRoutine = Standard_GetStatus; - } - } - - } - - /*GET CONFIGURATION*/ - else if (Request_No == GET_CONFIGURATION) - { - if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) - { - CopyRoutine = Standard_GetConfiguration; - } - } - /*GET INTERFACE*/ - else if (Request_No == GET_INTERFACE) - { - if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) - && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0) - && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001) - && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)) - { - CopyRoutine = Standard_GetInterface; - } - - } - - if (CopyRoutine) - { - pInformation->Ctrl_Info.Usb_wOffset = wOffset; - pInformation->Ctrl_Info.CopyData = CopyRoutine; - /* sb in the original the cast to word was directly */ - /* now the cast is made step by step */ - (*CopyRoutine)(0); - Result = USB_SUCCESS; - } - else - { - Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest); - if (Result == USB_NOT_READY) - { - pInformation->ControlState = PAUSE; - return; - } - } - - if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) - { - /* Data is not ready, wait it */ - pInformation->ControlState = PAUSE; - return; - } - if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0)) - { - /* Unsupported request */ - pInformation->ControlState = STALLED; - return; - } - - - if (ValBit(pInformation->USBbmRequestType, 7)) - { - /* Device ==> Host */ - __IO uint32_t wLength = pInformation->USBwLength; - - /* Restrict the data length to be the one host asks for */ - if (pInformation->Ctrl_Info.Usb_wLength > wLength) - { - pInformation->Ctrl_Info.Usb_wLength = wLength; - } - - else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength) - { - if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) - { - Data_Mul_MaxPacketSize = FALSE; - } - else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0) - { - Data_Mul_MaxPacketSize = TRUE; - } - } - - pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize; - DataStageIn(); - } - else - { - pInformation->ControlState = OUT_DATA; - vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */ - } - - return; -} - -/******************************************************************************* -* Function Name : Setup0_Process -* Description : Get the device request data and dispatch to individual process. -* Input : None. -* Output : None. -* Return : Post0_Process. -*******************************************************************************/ -uint8_t Setup0_Process(void) -{ - - union - { - uint8_t* b; - uint16_t* w; - } pBuf; - -#ifdef STM32F10X_CL - USB_OTG_EP *ep; - uint16_t offset = 0; - - ep = OTGD_FS_PCD_GetOutEP(ENDP0); - pBuf.b = ep->xfer_buff; - - OTGD_FS_EP0StartXfer(ep); -#else - uint16_t offset = 1; - - pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */ -#endif /* STM32F10X_CL */ - - if (pInformation->ControlState != PAUSE) - { - pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */ - pInformation->USBbRequest = *pBuf.b++; /* bRequest */ - pBuf.w += offset; /* word not accessed because of 32 bits addressing */ - pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */ - pBuf.w += offset; /* word not accessed because of 32 bits addressing */ - pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */ - pBuf.w += offset; /* word not accessed because of 32 bits addressing */ - pInformation->USBwLength = *pBuf.w; /* wLength */ - } - - pInformation->ControlState = SETTING_UP; - if (pInformation->USBwLength == 0) - { - /* Setup with no data stage */ - NoData_Setup0(); - } - else - { - /* Setup with data stage */ - Data_Setup0(); - } - return Post0_Process(); -} - -/******************************************************************************* -* Function Name : In0_Process -* Description : Process the IN token on all default endpoint. -* Input : None. -* Output : None. -* Return : Post0_Process. -*******************************************************************************/ -uint8_t In0_Process(void) -{ - uint32_t ControlState = pInformation->ControlState; - - if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) - { - DataStageIn(); - /* ControlState may be changed outside the function */ - ControlState = pInformation->ControlState; - } - - else if (ControlState == WAIT_STATUS_IN) - { - if ((pInformation->USBbRequest == SET_ADDRESS) && - (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) - { - SetDeviceAddress(pInformation->USBwValue0); - pUser_Standard_Requests->User_SetDeviceAddress(); - } - (*pProperty->Process_Status_IN)(); - ControlState = STALLED; - } - - else - { - ControlState = STALLED; - } - - pInformation->ControlState = ControlState; - - return Post0_Process(); -} - -/******************************************************************************* -* Function Name : Out0_Process -* Description : Process the OUT token on all default endpoint. -* Input : None. -* Output : None. -* Return : Post0_Process. -*******************************************************************************/ -uint8_t Out0_Process(void) -{ - uint32_t ControlState = pInformation->ControlState; - - if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) - { - /* host aborts the transfer before finish */ - ControlState = STALLED; - } - else if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA)) - { - DataStageOut(); - ControlState = pInformation->ControlState; /* may be changed outside the function */ - } - - else if (ControlState == WAIT_STATUS_OUT) - { - (*pProperty->Process_Status_OUT)(); - #ifndef STM32F10X_CL - ControlState = STALLED; - #endif /* STM32F10X_CL */ - } - - - /* Unexpect state, STALL the endpoint */ - else - { - ControlState = STALLED; - } - - pInformation->ControlState = ControlState; - - return Post0_Process(); -} - -/******************************************************************************* -* Function Name : Post0_Process -* Description : Stall the Endpoint 0 in case of error. -* Input : None. -* Output : None. -* Return : - 0 if the control State is in PAUSE -* - 1 if not. -*******************************************************************************/ -uint8_t Post0_Process(void) -{ -#ifdef STM32F10X_CL - USB_OTG_EP *ep; -#endif /* STM32F10X_CL */ - - SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); - - if (pInformation->ControlState == STALLED) - { - vSetEPRxStatus(EP_RX_STALL); - vSetEPTxStatus(EP_TX_STALL); - } - -#ifdef STM32F10X_CL - else if ((pInformation->ControlState == OUT_DATA) || - (pInformation->ControlState == WAIT_STATUS_OUT)) - { - ep = OTGD_FS_PCD_GetInEP(0); - ep->is_in = 0; - OTGD_FS_EP0StartXfer(ep); - - vSetEPTxStatus(EP_TX_VALID); - } - - else if ((pInformation->ControlState == IN_DATA) || - (pInformation->ControlState == WAIT_STATUS_IN)) - { - ep = OTGD_FS_PCD_GetInEP(0); - ep->is_in = 1; - OTGD_FS_EP0StartXfer(ep); - } -#endif /* STM32F10X_CL */ - - return (pInformation->ControlState == PAUSE); -} - -/******************************************************************************* -* Function Name : SetDeviceAddress. -* Description : Set the device and all the used Endpoints addresses. -* Input : - Val: device adress. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetDeviceAddress(uint8_t Val) -{ -#ifdef STM32F10X_CL - OTGD_FS_PCD_EP_SetAddress ((uint8_t)Val); -#else - uint32_t i; - uint32_t nEP = Device_Table.Total_Endpoint; - - /* set address in every used endpoint */ - for (i = 0; i < nEP; i++) - { - _SetEPAddress((uint8_t)i, (uint8_t)i); - } /* for */ - _SetDADDR(Val | DADDR_EF); /* set device address and enable function */ -#endif /* STM32F10X_CL */ -} - -/******************************************************************************* -* Function Name : NOP_Process -* Description : No operation function. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void NOP_Process(void) -{ -} - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/usb_init.c b/STM32_USB-FS-Device_Driver/src/usb_init.c deleted file mode 100644 index d318106..0000000 --- a/STM32_USB-FS-Device_Driver/src/usb_init.c +++ /dev/null @@ -1,63 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_init.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Initialization routines & global variables -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* The number of current endpoint, it will be used to specify an endpoint */ - uint8_t EPindex; -/* The number of current device, it is an index to the Device_Table */ -/* uint8_t Device_no; */ -/* Points to the DEVICE_INFO structure of current device */ -/* The purpose of this register is to speed up the execution */ -DEVICE_INFO *pInformation; -/* Points to the DEVICE_PROP structure of current device */ -/* The purpose of this register is to speed up the execution */ -const DEVICE_PROP *pProperty; -/* Temporary save the state of Rx & Tx status. */ -/* Whenever the Rx or Tx state is changed, its value is saved */ -/* in this variable first and will be set to the EPRB or EPRA */ -/* at the end of interrupt process */ -uint16_t SaveState ; -uint16_t wInterrupt_Mask; -DEVICE_INFO Device_Info; -const USER_STANDARD_REQUESTS *pUser_Standard_Requests; - -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : USB_Init -* Description : USB system initialization -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void USB_Init(void) -{ - pInformation = &Device_Info; - pInformation->ControlState = 2; - pProperty = &Device_Property; - pUser_Standard_Requests = &User_Standard_Requests; - /* Initialize devices one by one */ - pProperty->Init(); -} - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/usb_int.c b/STM32_USB-FS-Device_Driver/src/usb_int.c deleted file mode 100644 index 00b9838..0000000 --- a/STM32_USB-FS-Device_Driver/src/usb_int.c +++ /dev/null @@ -1,188 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_int.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Endpoint CTR (Low and High) interrupt's service routines -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ -#ifndef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -__IO uint16_t SaveRState; -__IO uint16_t SaveTState; - -/* Extern variables ----------------------------------------------------------*/ -extern void (*pEpInt_IN[7])(void); /* Handles IN interrupts */ -extern void (*pEpInt_OUT[7])(void); /* Handles OUT interrupts */ - -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : CTR_LP. -* Description : Low priority Endpoint Correct Transfer interrupt's service -* routine. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void CTR_LP(void) -{ - __IO uint16_t wEPVal = 0; - /* stay in loop while pending ints */ - while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) - { - /* extract highest priority endpoint number */ - EPindex = (uint8_t)(wIstr & ISTR_EP_ID); - if (EPindex == 0) - { - /* Decode and service control endpoint interrupt */ - /* calling related service routine */ - /* (Setup0_Process, In0_Process, Out0_Process) */ - - /* save RX & TX status */ - /* and set both to NAK */ - - - SaveRState = _GetENDPOINT(ENDP0); - SaveTState = SaveRState & EPTX_STAT; - SaveRState &= EPRX_STAT; - - _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK); - - /* DIR bit = origin of the interrupt */ - - if ((wIstr & ISTR_DIR) == 0) - { - /* DIR = 0 */ - - /* DIR = 0 => IN int */ - /* DIR = 0 implies that (EP_CTR_TX = 1) always */ - - - _ClearEP_CTR_TX(ENDP0); - In0_Process(); - - /* before terminate set Tx & Rx status */ - - _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); - return; - } - else - { - /* DIR = 1 */ - - /* DIR = 1 & CTR_RX => SETUP or OUT int */ - /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ - - wEPVal = _GetENDPOINT(ENDP0); - - if ((wEPVal &EP_SETUP) != 0) - { - _ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */ - Setup0_Process(); - /* before terminate set Tx & Rx status */ - - _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); - return; - } - - else if ((wEPVal & EP_CTR_RX) != 0) - { - _ClearEP_CTR_RX(ENDP0); - Out0_Process(); - /* before terminate set Tx & Rx status */ - - _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); - return; - } - } - }/* if(EPindex == 0) */ - else - { - /* Decode and service non control endpoints interrupt */ - - /* process related endpoint register */ - wEPVal = _GetENDPOINT(EPindex); - if ((wEPVal & EP_CTR_RX) != 0) - { - /* clear int flag */ - _ClearEP_CTR_RX(EPindex); - - /* call OUT service function */ - (*pEpInt_OUT[EPindex-1])(); - - } /* if((wEPVal & EP_CTR_RX) */ - - if ((wEPVal & EP_CTR_TX) != 0) - { - /* clear int flag */ - _ClearEP_CTR_TX(EPindex); - - /* call IN service function */ - (*pEpInt_IN[EPindex-1])(); - } /* if((wEPVal & EP_CTR_TX) != 0) */ - - }/* if(EPindex == 0) else */ - - }/* while(...) */ -} - -/******************************************************************************* -* Function Name : CTR_HP. -* Description : High Priority Endpoint Correct Transfer interrupt's service -* routine. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void CTR_HP(void) -{ - uint32_t wEPVal = 0; - - while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) - { - _SetISTR((uint16_t)CLR_CTR); /* clear CTR flag */ - /* extract highest priority endpoint number */ - EPindex = (uint8_t)(wIstr & ISTR_EP_ID); - /* process related endpoint register */ - wEPVal = _GetENDPOINT(EPindex); - if ((wEPVal & EP_CTR_RX) != 0) - { - /* clear int flag */ - _ClearEP_CTR_RX(EPindex); - - /* call OUT service function */ - (*pEpInt_OUT[EPindex-1])(); - - } /* if((wEPVal & EP_CTR_RX) */ - else if ((wEPVal & EP_CTR_TX) != 0) - { - /* clear int flag */ - _ClearEP_CTR_TX(EPindex); - - /* call IN service function */ - (*pEpInt_IN[EPindex-1])(); - - - } /* if((wEPVal & EP_CTR_TX) != 0) */ - - }/* while(...) */ -} - -#endif /* STM32F10X_CL */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/usb_mem.c b/STM32_USB-FS-Device_Driver/src/usb_mem.c deleted file mode 100644 index cdffaa9..0000000 --- a/STM32_USB-FS-Device_Driver/src/usb_mem.c +++ /dev/null @@ -1,75 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_mem.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Utility functions for memory transfers to/from PMA -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ -#ifndef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ -/******************************************************************************* -* Function Name : UserToPMABufferCopy -* Description : Copy a buffer from user memory area to packet memory area (PMA) -* Input : - pbUsrBuf: pointer to user memory area. -* - wPMABufAddr: address into PMA. -* - wNBytes: no. of bytes to be copied. -* Output : None. -* Return : None . -*******************************************************************************/ -void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) -{ - uint32_t n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ - uint32_t i, temp1, temp2; - uint16_t *pdwVal; - pdwVal = (uint16_t *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - temp1 = (uint16_t) * pbUsrBuf; - pbUsrBuf++; - temp2 = temp1 | (uint16_t) * pbUsrBuf << 8; - *pdwVal++ = temp2; - pdwVal++; - pbUsrBuf++; - } -} -/******************************************************************************* -* Function Name : PMAToUserBufferCopy -* Description : Copy a buffer from user memory area to packet memory area (PMA) -* Input : - pbUsrBuf = pointer to user memory area. -* - wPMABufAddr = address into PMA. -* - wNBytes = no. of bytes to be copied. -* Output : None. -* Return : None. -*******************************************************************************/ -void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) -{ - uint32_t n = (wNBytes + 1) >> 1;/* /2*/ - uint32_t i; - uint32_t *pdwVal; - pdwVal = (uint32_t *)(wPMABufAddr * 2 + PMAAddr); - for (i = n; i != 0; i--) - { - *(uint16_t*)pbUsrBuf++ = *pdwVal++; - pbUsrBuf++; - } -} - -#endif /* STM32F10X_CL */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/usb_regs.c b/STM32_USB-FS-Device_Driver/src/usb_regs.c deleted file mode 100644 index a2e923e..0000000 --- a/STM32_USB-FS-Device_Driver/src/usb_regs.c +++ /dev/null @@ -1,750 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_regs.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Interface functions to USB cell registers -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ -#ifndef STM32F10X_CL - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : SetCNTR. -* Description : Set the CNTR register value. -* Input : wRegValue: new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetCNTR(uint16_t wRegValue) -{ - _SetCNTR(wRegValue); -} - -/******************************************************************************* -* Function Name : GetCNTR. -* Description : returns the CNTR register value. -* Input : None. -* Output : None. -* Return : CNTR register Value. -*******************************************************************************/ -uint16_t GetCNTR(void) -{ - return(_GetCNTR()); -} - -/******************************************************************************* -* Function Name : SetISTR. -* Description : Set the ISTR register value. -* Input : wRegValue: new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetISTR(uint16_t wRegValue) -{ - _SetISTR(wRegValue); -} - -/******************************************************************************* -* Function Name : GetISTR -* Description : Returns the ISTR register value. -* Input : None. -* Output : None. -* Return : ISTR register Value -*******************************************************************************/ -uint16_t GetISTR(void) -{ - return(_GetISTR()); -} - -/******************************************************************************* -* Function Name : GetFNR -* Description : Returns the FNR register value. -* Input : None. -* Output : None. -* Return : FNR register Value -*******************************************************************************/ -uint16_t GetFNR(void) -{ - return(_GetFNR()); -} - -/******************************************************************************* -* Function Name : SetDADDR -* Description : Set the DADDR register value. -* Input : wRegValue: new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetDADDR(uint16_t wRegValue) -{ - _SetDADDR(wRegValue); -} - -/******************************************************************************* -* Function Name : GetDADDR -* Description : Returns the DADDR register value. -* Input : None. -* Output : None. -* Return : DADDR register Value -*******************************************************************************/ -uint16_t GetDADDR(void) -{ - return(_GetDADDR()); -} - -/******************************************************************************* -* Function Name : SetBTABLE -* Description : Set the BTABLE. -* Input : wRegValue: New register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetBTABLE(uint16_t wRegValue) -{ - _SetBTABLE(wRegValue); -} - -/******************************************************************************* -* Function Name : GetBTABLE. -* Description : Returns the BTABLE register value. -* Input : None. -* Output : None. -* Return : BTABLE address. -*******************************************************************************/ -uint16_t GetBTABLE(void) -{ - return(_GetBTABLE()); -} - -/******************************************************************************* -* Function Name : SetENDPOINT -* Description : Setthe Endpoint register value. -* Input : bEpNum: Endpoint Number. -* wRegValue. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetENDPOINT(uint8_t bEpNum, uint16_t wRegValue) -{ - _SetENDPOINT(bEpNum, wRegValue); -} - -/******************************************************************************* -* Function Name : GetENDPOINT -* Description : Return the Endpoint register value. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint register value. -*******************************************************************************/ -uint16_t GetENDPOINT(uint8_t bEpNum) -{ - return(_GetENDPOINT(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPType -* Description : sets the type in the endpoint register. -* Input : bEpNum: Endpoint Number. -* wType: type definition. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPType(uint8_t bEpNum, uint16_t wType) -{ - _SetEPType(bEpNum, wType); -} - -/******************************************************************************* -* Function Name : GetEPType -* Description : Returns the endpoint type. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Type -*******************************************************************************/ -uint16_t GetEPType(uint8_t bEpNum) -{ - return(_GetEPType(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPTxStatus -* Description : Set the status of Tx endpoint. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxStatus(uint8_t bEpNum, uint16_t wState) -{ - _SetEPTxStatus(bEpNum, wState); -} - -/******************************************************************************* -* Function Name : SetEPRxStatus -* Description : Set the status of Rx endpoint. -* Input : bEpNum: Endpoint Number. -* wState: new state. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxStatus(uint8_t bEpNum, uint16_t wState) -{ - _SetEPRxStatus(bEpNum, wState); -} - -/******************************************************************************* -* Function Name : SetDouBleBuffEPStall -* Description : sets the status for Double Buffer Endpoint to STALL -* Input : bEpNum: Endpoint Number. -* bDir: Endpoint direction. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetDouBleBuffEPStall(uint8_t bEpNum, uint8_t bDir) -{ - uint16_t Endpoint_DTOG_Status; - Endpoint_DTOG_Status = GetENDPOINT(bEpNum); - if (bDir == EP_DBUF_OUT) - { /* OUT double buffered endpoint */ - _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPRX_DTOG1); - } - else if (bDir == EP_DBUF_IN) - { /* IN double buffered endpoint */ - _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPTX_DTOG1); - } -} - -/******************************************************************************* -* Function Name : GetEPTxStatus -* Description : Returns the endpoint Tx status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint TX Status -*******************************************************************************/ -uint16_t GetEPTxStatus(uint8_t bEpNum) -{ - return(_GetEPTxStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : GetEPRxStatus -* Description : Returns the endpoint Rx status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint RX Status -*******************************************************************************/ -uint16_t GetEPRxStatus(uint8_t bEpNum) -{ - return(_GetEPRxStatus(bEpNum)); -} - -/******************************************************************************* -* Function Name : SetEPTxValid -* Description : Valid the endpoint Tx Status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxValid(uint8_t bEpNum) -{ - _SetEPTxStatus(bEpNum, EP_TX_VALID); -} - -/******************************************************************************* -* Function Name : SetEPRxValid -* Description : Valid the endpoint Rx Status. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxValid(uint8_t bEpNum) -{ - _SetEPRxStatus(bEpNum, EP_RX_VALID); -} - -/******************************************************************************* -* Function Name : SetEP_KIND -* Description : Clear the EP_KIND bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEP_KIND(uint8_t bEpNum) -{ - _SetEP_KIND(bEpNum); -} - -/******************************************************************************* -* Function Name : ClearEP_KIND -* Description : set the EP_KIND bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEP_KIND(uint8_t bEpNum) -{ - _ClearEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : Clear_Status_Out -* Description : Clear the Status Out of the related Endpoint -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void Clear_Status_Out(uint8_t bEpNum) -{ - _ClearEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : Set_Status_Out -* Description : Set the Status Out of the related Endpoint -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void Set_Status_Out(uint8_t bEpNum) -{ - _SetEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : SetEPDoubleBuff -* Description : Enable the double buffer feature for the endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDoubleBuff(uint8_t bEpNum) -{ - _SetEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : ClearEPDoubleBuff -* Description : Disable the double buffer feature for the endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEPDoubleBuff(uint8_t bEpNum) -{ - _ClearEP_KIND(bEpNum); -} -/******************************************************************************* -* Function Name : GetTxStallStatus -* Description : Returns the Stall status of the Tx endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Tx Stall status. -*******************************************************************************/ -uint16_t GetTxStallStatus(uint8_t bEpNum) -{ - return(_GetTxStallStatus(bEpNum)); -} -/******************************************************************************* -* Function Name : GetRxStallStatus -* Description : Returns the Stall status of the Rx endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx Stall status. -*******************************************************************************/ -uint16_t GetRxStallStatus(uint8_t bEpNum) -{ - return(_GetRxStallStatus(bEpNum)); -} -/******************************************************************************* -* Function Name : ClearEP_CTR_RX -* Description : Clear the CTR_RX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEP_CTR_RX(uint8_t bEpNum) -{ - _ClearEP_CTR_RX(bEpNum); -} -/******************************************************************************* -* Function Name : ClearEP_CTR_TX -* Description : Clear the CTR_TX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearEP_CTR_TX(uint8_t bEpNum) -{ - _ClearEP_CTR_TX(bEpNum); -} -/******************************************************************************* -* Function Name : ToggleDTOG_RX -* Description : Toggle the DTOG_RX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ToggleDTOG_RX(uint8_t bEpNum) -{ - _ToggleDTOG_RX(bEpNum); -} -/******************************************************************************* -* Function Name : ToggleDTOG_TX -* Description : Toggle the DTOG_TX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ToggleDTOG_TX(uint8_t bEpNum) -{ - _ToggleDTOG_TX(bEpNum); -} -/******************************************************************************* -* Function Name : ClearDTOG_RX. -* Description : Clear the DTOG_RX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearDTOG_RX(uint8_t bEpNum) -{ - _ClearDTOG_RX(bEpNum); -} -/******************************************************************************* -* Function Name : ClearDTOG_TX. -* Description : Clear the DTOG_TX bit. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -void ClearDTOG_TX(uint8_t bEpNum) -{ - _ClearDTOG_TX(bEpNum); -} -/******************************************************************************* -* Function Name : SetEPAddress -* Description : Set the endpoint address. -* Input : bEpNum: Endpoint Number. -* bAddr: New endpoint address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPAddress(uint8_t bEpNum, uint8_t bAddr) -{ - _SetEPAddress(bEpNum, bAddr); -} -/******************************************************************************* -* Function Name : GetEPAddress -* Description : Get the endpoint address. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint address. -*******************************************************************************/ -uint8_t GetEPAddress(uint8_t bEpNum) -{ - return(_GetEPAddress(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPTxAddr -* Description : Set the endpoint Tx buffer address. -* Input : bEpNum: Endpoint Number. -* wAddr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxAddr(uint8_t bEpNum, uint16_t wAddr) -{ - _SetEPTxAddr(bEpNum, wAddr); -} -/******************************************************************************* -* Function Name : SetEPRxAddr -* Description : Set the endpoint Rx buffer address. -* Input : bEpNum: Endpoint Number. -* wAddr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxAddr(uint8_t bEpNum, uint16_t wAddr) -{ - _SetEPRxAddr(bEpNum, wAddr); -} -/******************************************************************************* -* Function Name : GetEPTxAddr -* Description : Returns the endpoint Tx buffer address. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx buffer address. -*******************************************************************************/ -uint16_t GetEPTxAddr(uint8_t bEpNum) -{ - return(_GetEPTxAddr(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPRxAddr. -* Description : Returns the endpoint Rx buffer address. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx buffer address. -*******************************************************************************/ -uint16_t GetEPRxAddr(uint8_t bEpNum) -{ - return(_GetEPRxAddr(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPTxCount. -* Description : Set the Tx count. -* Input : bEpNum: Endpoint Number. -* wCount: new count value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPTxCount(uint8_t bEpNum, uint16_t wCount) -{ - _SetEPTxCount(bEpNum, wCount); -} -/******************************************************************************* -* Function Name : SetEPCountRxReg. -* Description : Set the Count Rx Register value. -* Input : *pdwReg: point to the register. -* wCount: the new register value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPCountRxReg(uint32_t *pdwReg, uint16_t wCount) -{ - _SetEPCountRxReg(dwReg, wCount); -} -/******************************************************************************* -* Function Name : SetEPRxCount -* Description : Set the Rx count. -* Input : bEpNum: Endpoint Number. -* wCount: the new count value. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPRxCount(uint8_t bEpNum, uint16_t wCount) -{ - _SetEPRxCount(bEpNum, wCount); -} -/******************************************************************************* -* Function Name : GetEPTxCount -* Description : Get the Tx count. -* Input : bEpNum: Endpoint Number. -* Output : None -* Return : Tx count value. -*******************************************************************************/ -uint16_t GetEPTxCount(uint8_t bEpNum) -{ - return(_GetEPTxCount(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPRxCount -* Description : Get the Rx count. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Rx count value. -*******************************************************************************/ -uint16_t GetEPRxCount(uint8_t bEpNum) -{ - return(_GetEPRxCount(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPDblBuffAddr -* Description : Set the addresses of the buffer 0 and 1. -* Input : bEpNum: Endpoint Number. -* wBuf0Addr: new address of buffer 0. -* wBuf1Addr: new address of buffer 1. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuffAddr(uint8_t bEpNum, uint16_t wBuf0Addr, uint16_t wBuf1Addr) -{ - _SetEPDblBuffAddr(bEpNum, wBuf0Addr, wBuf1Addr); -} -/******************************************************************************* -* Function Name : SetEPDblBuf0Addr -* Description : Set the Buffer 1 address. -* Input : bEpNum: Endpoint Number -* wBuf0Addr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf0Addr(uint8_t bEpNum, uint16_t wBuf0Addr) -{ - _SetEPDblBuf0Addr(bEpNum, wBuf0Addr); -} -/******************************************************************************* -* Function Name : SetEPDblBuf1Addr -* Description : Set the Buffer 1 address. -* Input : bEpNum: Endpoint Number -* wBuf1Addr: new address. -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf1Addr(uint8_t bEpNum, uint16_t wBuf1Addr) -{ - _SetEPDblBuf1Addr(bEpNum, wBuf1Addr); -} -/******************************************************************************* -* Function Name : GetEPDblBuf0Addr -* Description : Returns the address of the Buffer 0. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : None. -*******************************************************************************/ -uint16_t GetEPDblBuf0Addr(uint8_t bEpNum) -{ - return(_GetEPDblBuf0Addr(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPDblBuf1Addr -* Description : Returns the address of the Buffer 1. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Address of the Buffer 1. -*******************************************************************************/ -uint16_t GetEPDblBuf1Addr(uint8_t bEpNum) -{ - return(_GetEPDblBuf1Addr(bEpNum)); -} -/******************************************************************************* -* Function Name : SetEPDblBuffCount -* Description : Set the number of bytes for a double Buffer -* endpoint. -* Input : bEpNum,bDir, wCount -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuffCount(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) -{ - _SetEPDblBuffCount(bEpNum, bDir, wCount); -} -/******************************************************************************* -* Function Name : SetEPDblBuf0Count -* Description : Set the number of bytes in the buffer 0 of a double Buffer -* endpoint. -* Input : bEpNum, bDir, wCount -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf0Count(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) -{ - _SetEPDblBuf0Count(bEpNum, bDir, wCount); -} -/******************************************************************************* -* Function Name : SetEPDblBuf1Count -* Description : Set the number of bytes in the buffer 0 of a double Buffer -* endpoint. -* Input : bEpNum, bDir, wCount -* Output : None. -* Return : None. -*******************************************************************************/ -void SetEPDblBuf1Count(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) -{ - _SetEPDblBuf1Count(bEpNum, bDir, wCount); -} -/******************************************************************************* -* Function Name : GetEPDblBuf0Count -* Description : Returns the number of byte received in the buffer 0 of a double -* Buffer endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Buffer 0 count -*******************************************************************************/ -uint16_t GetEPDblBuf0Count(uint8_t bEpNum) -{ - return(_GetEPDblBuf0Count(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPDblBuf1Count -* Description : Returns the number of data received in the buffer 1 of a double -* Buffer endpoint. -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : Endpoint Buffer 1 count. -*******************************************************************************/ -uint16_t GetEPDblBuf1Count(uint8_t bEpNum) -{ - return(_GetEPDblBuf1Count(bEpNum)); -} -/******************************************************************************* -* Function Name : GetEPDblBufDir -* Description : gets direction of the double buffered endpoint -* Input : bEpNum: Endpoint Number. -* Output : None. -* Return : EP_DBUF_OUT, EP_DBUF_IN, -* EP_DBUF_ERR if the endpoint counter not yet programmed. -*******************************************************************************/ -EP_DBUF_DIR GetEPDblBufDir(uint8_t bEpNum) -{ - if ((uint16_t)(*_pEPRxCount(bEpNum) & 0xFC00) != 0) - return(EP_DBUF_OUT); - else if (((uint16_t)(*_pEPTxCount(bEpNum)) & 0x03FF) != 0) - return(EP_DBUF_IN); - else - return(EP_DBUF_ERR); -} -/******************************************************************************* -* Function Name : FreeUserBuffer -* Description : free buffer used from the application realizing it to the line - toggles bit SW_BUF in the double buffered endpoint register -* Input : bEpNum, bDir -* Output : None. -* Return : None. -*******************************************************************************/ -void FreeUserBuffer(uint8_t bEpNum, uint8_t bDir) -{ - if (bDir == EP_DBUF_OUT) - { /* OUT double buffered endpoint */ - _ToggleDTOG_TX(bEpNum); - } - else if (bDir == EP_DBUF_IN) - { /* IN double buffered endpoint */ - _ToggleDTOG_RX(bEpNum); - } -} - -/******************************************************************************* -* Function Name : ToWord -* Description : merge two byte in a word. -* Input : bh: byte high, bl: bytes low. -* Output : None. -* Return : resulted word. -*******************************************************************************/ -uint16_t ToWord(uint8_t bh, uint8_t bl) -{ - uint16_t wRet; - wRet = (uint16_t)bl | ((uint16_t)bh << 8); - return(wRet); -} -/******************************************************************************* -* Function Name : ByteSwap -* Description : Swap two byte in a word. -* Input : wSwW: word to Swap. -* Output : None. -* Return : resulted word. -*******************************************************************************/ -uint16_t ByteSwap(uint16_t wSwW) -{ - uint8_t bTemp; - uint16_t wRet; - bTemp = (uint8_t)(wSwW & 0xff); - wRet = (wSwW >> 8) | ((uint16_t)bTemp << 8); - return(wRet); -} - -#endif /* STM32F10X_CL */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/STM32_USB-FS-Device_Driver/src/usb_sil.c b/STM32_USB-FS-Device_Driver/src/usb_sil.c deleted file mode 100644 index 1c290da..0000000 --- a/STM32_USB-FS-Device_Driver/src/usb_sil.c +++ /dev/null @@ -1,126 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_sil.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Simplified Interface Layer for Global Initialization and -* Endpoint Rea/Write operations. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : USB_SIL_Init -* Description : Initialize the USB Device IP and the Endpoint 0. -* Input : None. -* Output : None. -* Return : Status. -*******************************************************************************/ -uint32_t USB_SIL_Init(void) -{ -#ifndef STM32F10X_CL - - /* USB interrupts initialization */ - /* clear pending interrupts */ - _SetISTR(0); - wInterrupt_Mask = IMR_MSK; - /* set interrupts mask */ - _SetCNTR(wInterrupt_Mask); - -#else - - /* Perform OTG Device initialization procedure (including EP0 init) */ - OTG_DEV_Init(); - -#endif /* STM32F10X_CL */ - - return 0; -} - -/******************************************************************************* -* Function Name : USB_SIL_Write -* Description : Write a buffer of data to a selected endpoint. -* Input : - bEpAddr: The address of the non control endpoint. -* - pBufferPointer: The pointer to the buffer of data to be written -* to the endpoint. -* - wBufferSize: Number of data to be written (in bytes). -* Output : None. -* Return : Status. -*******************************************************************************/ -uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize) -{ -#ifndef STM32F10X_CL - - /* Use the memory interface function to write to the selected endpoint */ - UserToPMABufferCopy(pBufferPointer, GetEPTxAddr(bEpAddr & 0x7F), wBufferSize); - - /* Update the data length in the control register */ - SetEPTxCount((bEpAddr & 0x7F), wBufferSize); - -#else - - /* Use the PCD interface layer function to write to the selected endpoint */ - OTGD_FS_PCD_EP_Write (bEpAddr, pBufferPointer, wBufferSize); - -#endif /* STM32F10X_CL */ - - return 0; -} - -/******************************************************************************* -* Function Name : USB_SIL_Read -* Description : Write a buffer of data to a selected endpoint. -* Input : - bEpAddr: The address of the non control endpoint. -* - pBufferPointer: The pointer to which will be saved the -* received data buffer. -* Output : None. -* Return : Number of received data (in Bytes). -*******************************************************************************/ -uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer) -{ - uint32_t DataLength = 0; - -#ifndef STM32F10X_CL - - /* Get the number of received data on the selected Endpoint */ - DataLength = GetEPRxCount(bEpAddr & 0x7F); - - /* Use the memory interface function to write to the selected endpoint */ - PMAToUserBufferCopy(pBufferPointer, GetEPRxAddr(bEpAddr & 0x7F), DataLength); - -#else - - USB_OTG_EP *ep; - - /* Get the structure pointer of the selected Endpoint */ - ep = OTGD_FS_PCD_GetOutEP(bEpAddr); - - /* Get the number of received data */ - DataLength = ep->xfer_len; - - /* Use the PCD interface layer function to read the selected endpoint */ - OTGD_FS_PCD_EP_Read (bEpAddr, pBufferPointer, DataLength); - -#endif /* STM32F10X_CL */ - - /* Return the number of received data */ - return DataLength; -} - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/hw_config.c b/Virtual_COM_Port/hw_config.c deleted file mode 100644 index 3f822c0..0000000 --- a/Virtual_COM_Port/hw_config.c +++ /dev/null @@ -1,113 +0,0 @@ -/******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** -* File Name : hw_config.c -* Author : MCD Application Team -* Version : V3.0.1 -* Date : 04/27/2009 -* Description : Hardware Configuration & Setup -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -#include "usb_prop.h" -#include "usb_desc.h" -#include "hw_config.h" -#include "platform_config.h" -#include "usb_pwr.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ - -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : Enter_LowPowerMode -* Description : Power-off system clocks and power while entering suspend mode -* Input : None. -* Return : None. -*******************************************************************************/ -void Enter_LowPowerMode(void) -{ - /* Set the device state to suspend */ - bDeviceState = SUSPENDED; -} - -/******************************************************************************* -* Function Name : Leave_LowPowerMode -* Description : Restores system clocks and power while exiting suspend mode -* Input : None. -* Return : None. -*******************************************************************************/ -void Leave_LowPowerMode(void) -{ - DEVICE_INFO *pInfo = &Device_Info; - - /* Set the device state to the correct state */ - if (pInfo->Current_Configuration != 0) { - /* Device configured */ - bDeviceState = CONFIGURED; - } else { - bDeviceState = ATTACHED; - } -} - -/******************************************************************************* -* Function Name : USB_Cable_Config -* Description : Software Connection/Disconnection of USB Cable -* Input : None. -* Return : Status -*******************************************************************************/ -void USB_Cable_Config (FunctionalState NewState) -{ - if (NewState != DISABLE) { - GPIO_ResetBits(GPIOC, GPIO_Pin_11); - } else { - GPIO_SetBits(GPIOC, GPIO_Pin_11); - } -} - -/******************************************************************************* -* Function Name : Get_SerialNum. -* Description : Create the serial number string descriptor. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Get_SerialNum(void) -{ - uint32_t Device_Serial0, Device_Serial1, Device_Serial2; -/* - Device_Serial0 = *(__IO uint32_t*)(0x1FFFF7E8); - Device_Serial1 = *(__IO uint32_t*)(0x1FFFF7EC); - Device_Serial2 = *(__IO uint32_t*)(0x1FFFF7F0); - - if (Device_Serial0 != 0) - { - Virtual_Com_Port_StringSerial[2] = (uint8_t)(Device_Serial0 & 0x000000FF); - Virtual_Com_Port_StringSerial[4] = (uint8_t)((Device_Serial0 & 0x0000FF00) >> 8); - Virtual_Com_Port_StringSerial[6] = (uint8_t)((Device_Serial0 & 0x00FF0000) >> 16); - Virtual_Com_Port_StringSerial[8] = (uint8_t)((Device_Serial0 & 0xFF000000) >> 24); - - Virtual_Com_Port_StringSerial[10] = (uint8_t)(Device_Serial1 & 0x000000FF); - Virtual_Com_Port_StringSerial[12] = (uint8_t)((Device_Serial1 & 0x0000FF00) >> 8); - Virtual_Com_Port_StringSerial[14] = (uint8_t)((Device_Serial1 & 0x00FF0000) >> 16); - Virtual_Com_Port_StringSerial[16] = (uint8_t)((Device_Serial1 & 0xFF000000) >> 24); - - Virtual_Com_Port_StringSerial[18] = (uint8_t)(Device_Serial2 & 0x000000FF); - Virtual_Com_Port_StringSerial[20] = (uint8_t)((Device_Serial2 & 0x0000FF00) >> 8); - Virtual_Com_Port_StringSerial[22] = (uint8_t)((Device_Serial2 & 0x00FF0000) >> 16); - Virtual_Com_Port_StringSerial[24] = (uint8_t)((Device_Serial2 & 0xFF000000) >> 24); - }*/ -} - -/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/hw_config.h b/Virtual_COM_Port/hw_config.h deleted file mode 100644 index e646777..0000000 --- a/Virtual_COM_Port/hw_config.h +++ /dev/null @@ -1,41 +0,0 @@ -/******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** -* File Name : hw_config.h -* Author : MCD Application Team -* Version : V3.0.1 -* Date : 04/27/2009 -* Description : Hardware Configuration & Setup -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __HW_CONFIG_H -#define __HW_CONFIG_H - -/* Includes ------------------------------------------------------------------*/ -#include "usb_type.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported define -----------------------------------------------------------*/ -#define MASS_MEMORY_START 0x04002000 -#define BULK_MAX_PACKET_SIZE 0x00000040 -#define LED_ON 0xF0 -#define LED_OFF 0xFF - -/* Exported functions ------------------------------------------------------- */ -void Enter_LowPowerMode(void); -void Leave_LowPowerMode(void); -void USB_Cable_Config (FunctionalState NewState); -void Get_SerialNum(void); - -/* External variables --------------------------------------------------------*/ - -#endif /*__HW_CONFIG_H*/ -/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/platform.h b/Virtual_COM_Port/platform.h deleted file mode 100644 index b7cd226..0000000 --- a/Virtual_COM_Port/platform.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef PLATFORM_H_ -#define PLATFORM_H_ - -#define LED_PIN GPIO_Pin_12 -#define LED_GPIO GPIOC - -#define LCD_E_PIN GPIO_Pin_10 -#define LCD_E_GPIO GPIOC - -#define LCD_RESET_PIN GPIO_Pin_7 -#define LCD_RESET_GPIO GPIOC - -#define LCD_DC_PIN GPIO_Pin_2 -#define LCD_DC_GPIO GPIOB - -#define TAMP_PIN GPIO_Pin_13 -#define TAMP_GPIO GPIOC - -#define WAKE_PIN GPIO_Pin_0 -#define WAKE_GPIO GPIOA - -#define JOY_CENTER_PIN GPIO_Pin_6 -#define JOY_CENTER_GPIO GPIOC - -#define NRF_CS_PIN GPIO_Pin_4 -#define NRF_CS_GPIO GPIOA - -#define NRF_CE_PIN GPIO_Pin_8 -#define NRF_CE_GPIO GPIOC - -#define NRF_IRQ_PIN GPIO_Pin_9 -#define NRF_IRQ_GPIO GPIOC - -#define ADIS_CS_PIN GPIO_Pin_10 -#define ADIS_CS_GPIO GPIOB - -#define ADIS_RESET_PIN GPIO_Pin_3 -#define ADIS_RESET_GPIO GPIOA - -#define LED_WRITE(x) GPIO_WriteBit(LED_GPIO, LED_PIN, x) - -#define LCD_DC_WRITE(x) GPIO_WriteBit(LCD_DC_GPIO, LCD_DC_PIN, x) -#define LCD_E_WRITE(x) GPIO_WriteBit(LCD_E_GPIO, LCD_E_PIN, x) -#define LCD_RESET_WRITE(x) GPIO_WriteBit(LCD_RESET_GPIO, LCD_RESET_PIN, x) - -#define TAMP_READ GPIO_ReadInputDataBit(TAMP_GPIO, TAMP_PIN) -#define WAKE_READ GPIO_ReadInputDataBit(WAKE_GPIO, WAKE_PIN) -#define JOY_CENTER_READ GPIO_ReadInputDataBit(JOY_CENTER_GPIO, JOY_CENTER_PIN) - -#define NRF_CE_WRITE(x) GPIO_WriteBit(NRF_CE_GPIO, NRF_CE_PIN, x) -#define NRF_CS_WRITE(x) GPIO_WriteBit(NRF_CS_GPIO, NRF_CS_PIN, x) -#define NRF_IRQ_READ GPIO_ReadInputDataBit(MRF_IRQ_GPIO, NRF_IRQ_PIN) - -#define ADIS_CS_WRITE(x) GPIO_WriteBit(ADIS_CS_GPIO, ADIS_CS_PIN, x) -#define ADIS_RESET_WRITE(x) GPIO_WriteBit(ADIS_RESET_GPIO, ADIS_RESET_PIN, x) -#endif - diff --git a/Virtual_COM_Port/platform_config.h b/Virtual_COM_Port/platform_config.h deleted file mode 100644 index f1fd83f..0000000 --- a/Virtual_COM_Port/platform_config.h +++ /dev/null @@ -1,52 +0,0 @@ -/******************** (C) COPYRIGHT 2009 STMicroelectronics ******************** -* File Name : platform_config.h -* Author : MCD Application Team -* Version : V3.0.1 -* Date : 04/27/2009 -* Description : Evaluation board specific configuration file. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __PLATFORM_CONFIG_H -#define __PLATFORM_CONFIG_H - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Uncomment the line corresponding to the STMicroelectronics evaluation board - used to run the example */ -#if !defined (USE_STM3210B_EVAL) && !defined (USE_STM3210E_EVAL) - //#define USE_STM3210B_EVAL - #define USE_STM3210E_EVAL -#endif - -/* Define the STM32F10x hardware depending on the used evaluation board */ -#ifdef USE_STM3210B_EVAL - - #define USB_DISCONNECT GPIOD - #define USB_DISCONNECT_PIN GPIO_Pin_9 - #define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOD - -#else /* USE_STM3210E_EVAL */ - - #define USB_DISCONNECT GPIOB - #define USB_DISCONNECT_PIN GPIO_Pin_14 - #define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOB - -#endif /* USE_STM3210B_EVAL */ - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -#endif /* __PLATFORM_CONFIG_H */ - -/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_conf.h b/Virtual_COM_Port/usb_conf.h deleted file mode 100644 index ecbe241..0000000 --- a/Virtual_COM_Port/usb_conf.h +++ /dev/null @@ -1,197 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_conf.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Virtual COM Port Demo configuration header -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_CONF_H -#define __USB_CONF_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -/* External variables --------------------------------------------------------*/ - -/*-------------------------------------------------------------*/ -/* EP_NUM */ -/* defines how many endpoints are used by the device */ -/*-------------------------------------------------------------*/ - -#define EP_NUM (4) - - -#ifndef STM32F10X_CL -/*-------------------------------------------------------------*/ -/* -------------- 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) -#define ENDP2_TXADDR (0x100) -#define ENDP3_RXADDR (0x110) - - -/*-------------------------------------------------------------*/ -/* ------------------- 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*/ -#endif /* STM32F10X_CL */ - -#ifdef STM32F10X_CL -/******************************************************************************* -* FIFO Size Configuration -* -* (i) Dedicated data FIFO SPRAM of 1.25 Kbytes = 1280 bytes = 320 32-bits words -* available for the endpoints IN and OUT. -* Device mode features: -* -1 bidirectional CTRL EP 0 -* -3 IN EPs to support any kind of Bulk, Interrupt or Isochronous transfer -* -3 OUT EPs to support any kind of Bulk, Interrupt or Isochronous transfer -* -* ii) Receive data FIFO size = RAM for setup packets + -* OUT endpoint control information + -* data OUT packets + miscellaneous -* Space = ONE 32-bits words -* --> RAM for setup packets = 4 * n + 6 space -* (n is the nbr of CTRL EPs the device core supports) -* --> OUT EP CTRL info = 1 space -* (one space for status information written to the FIFO along with each -* received packet) -* --> data OUT packets = (Largest Packet Size / 4) + 1 spaces -* (MINIMUM to receive packets) -* --> OR data OUT packets = at least 2*(Largest Packet Size / 4) + 1 spaces -* (if high-bandwidth EP is enabled or multiple isochronous EPs) -* --> miscellaneous = 1 space per OUT EP -* (one space for transfer complete status information also pushed to the -* FIFO with each endpoint's last packet) -* -* (iii)MINIMUM RAM space required for each IN EP Tx FIFO = MAX packet size for -* that particular IN EP. More space allocated in the IN EP Tx FIFO results -* in a better performance on the USB and can hide latencies on the AHB. -* -* (iv) TXn min size = 16 words. (n : Transmit FIFO index) -* (v) When a TxFIFO is not used, the Configuration should be as follows: -* case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes) -* --> Txm can use the space allocated for Txn. -* case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes) -* --> Txn should be configured with the minimum space of 16 words -* (vi) The FIFO is used optimally when used TxFIFOs are allocated in the top -* of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones. -*******************************************************************************/ - -#define RX_FIFO_SIZE 128 -#define TX0_FIFO_SIZE 64 -#define TX1_FIFO_SIZE 64 -#define TX2_FIFO_SIZE 16 -#define TX3_FIFO_SIZE 16 - -/* OTGD-FS-DEVICE IP interrupts Enable definitions */ -/* Uncomment the define to enable the selected interrupt */ -//#define INTR_MODEMISMATCH -#define INTR_SOFINTR -#define INTR_RXSTSQLVL /* Mandatory */ -//#define INTR_NPTXFEMPTY -//#define INTR_GINNAKEFF -//#define INTR_GOUTNAKEFF -//#define INTR_ERLYSUSPEND -#define INTR_USBSUSPEND /* Mandatory */ -#define INTR_USBRESET /* Mandatory */ -#define INTR_ENUMDONE /* Mandatory */ -//#define INTR_ISOOUTDROP -//#define INTR_EOPFRAME -//#define INTR_EPMISMATCH -#define INTR_INEPINTR /* Mandatory */ -#define INTR_OUTEPINTR /* Mandatory */ -//#define INTR_INCOMPLISOIN -//#define INTR_INCOMPLISOOUT -#define INTR_WKUPINTR /* Mandatory */ - -/* OTGD-FS-DEVICE IP interrupts subroutines */ -/* Comment the define to enable the selected interrupt subroutine and replace it - by user code */ -#define INTR_MODEMISMATCH_Callback NOP_Process -#define INTR_SOFINTR_Callback NOP_Process -#define INTR_RXSTSQLVL_Callback NOP_Process -#define INTR_NPTXFEMPTY_Callback NOP_Process -#define INTR_NPTXFEMPTY_Callback NOP_Process -#define INTR_GINNAKEFF_Callback NOP_Process -#define INTR_GOUTNAKEFF_Callback NOP_Process -#define INTR_ERLYSUSPEND_Callback NOP_Process -#define INTR_USBSUSPEND_Callback NOP_Process -#define INTR_USBRESET_Callback NOP_Process -#define INTR_ENUMDONE_Callback NOP_Process -#define INTR_ISOOUTDROP_Callback NOP_Process -#define INTR_EOPFRAME_Callback NOP_Process -#define INTR_EPMISMATCH_Callback NOP_Process -#define INTR_INEPINTR_Callback NOP_Process -#define INTR_OUTEPINTR_Callback NOP_Process -#define INTR_INCOMPLISOIN_Callback NOP_Process -#define INTR_INCOMPLISOOUT_Callback NOP_Process -#define INTR_WKUPINTR_Callback NOP_Process - -/* Isochronous data update */ -#define INTR_RXSTSQLVL_ISODU_Callback NOP_Process - -/* Isochronous transfer parameters */ -/* Size of a single Isochronous buffer (size of a single transfer) */ -#define ISOC_BUFFER_SZE 1 -/* Number of sub-buffers (number of single buffers/transfers), should be even */ -#define NUM_SUB_BUFFERS 2 - -#endif /* STM32F10X_CL */ - - -/* CTR service routines */ -/* associated to defined endpoints */ -/*#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 /* __USB_CONF_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_desc.c b/Virtual_COM_Port/usb_desc.c deleted file mode 100644 index 80f5d52..0000000 --- a/Virtual_COM_Port/usb_desc.c +++ /dev/null @@ -1,161 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_desc.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Descriptors for Virtual Com Port Demo -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -#include "usb_desc.h" - -/* USB Standard Device Descriptor */ -const uint8_t Virtual_Com_Port_DeviceDescriptor[] = - { - 0x12, /* bLength */ - USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x00, - 0x02, /* bcdUSB = 2.00 */ - 0x02, /* bDeviceClass: CDC */ - 0x00, /* bDeviceSubClass */ - 0x00, /* bDeviceProtocol */ - 0x40, /* bMaxPacketSize0 */ - 0x83, - 0x04, /* idVendor = 0x0483 */ - 0x40, - 0x57, /* idProduct = 0x7540 */ - 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 */ - }; - -const uint8_t Virtual_Com_Port_ConfigDescriptor[] = - { - /*Configuation Descriptor*/ - 0x09, /* bLength: Configuation Descriptor size */ - USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ - VIRTUAL_COM_PORT_SIZ_CONFIG_DESC, /* wTotalLength:no of returned bytes */ - 0x00, - 0x02, /* bNumInterfaces: 2 interface */ - 0x01, /* bConfigurationValue: Configuration value */ - 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ - 0xC0, /* bmAttributes: self powered */ - 0x32, /* MaxPower 0 mA */ - /*Interface Descriptor*/ - 0x09, /* bLength: Interface Descriptor size */ - USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ - /* Interface descriptor type */ - 0x00, /* 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*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Managment Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ - 0x01, /* bDataInterface: 1 */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ - 0x00, /* bMasterInterface: Communication class interface */ - 0x01, /* bSlaveInterface0: Data Class Interface */ - /*Endpoint 2 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ - 0x82, /* bEndpointAddress: (IN2) */ - 0x03, /* bmAttributes: Interrupt */ - VIRTUAL_COM_PORT_INT_SIZE, /* wMaxPacketSize: */ - 0x00, - 0xFF, /* bInterval: */ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ - 0x01, /* 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*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ - 0x03, /* bEndpointAddress: (OUT3) */ - 0x02, /* bmAttributes: Bulk */ - VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */ - 0x00, - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint 1 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ - 0x81, /* bEndpointAddress: (IN1) */ - 0x02, /* bmAttributes: Bulk */ - VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */ - 0x00, - 0x00 /* bInterval */ - }; - -/* USB String Descriptors */ -const uint8_t Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID] = - { - VIRTUAL_COM_PORT_SIZ_STRING_LANGID, - USB_STRING_DESCRIPTOR_TYPE, - 0x09, - 0x04 /* LangID = 0x0409: U.S. English */ - }; - -const uint8_t Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR] = - { - VIRTUAL_COM_PORT_SIZ_STRING_VENDOR, /* Size of Vendor string */ - USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType*/ - /* Manufacturer: "STMicroelectronics" */ - 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, - 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, - 'c', 0, 's', 0 - }; - -const uint8_t Virtual_Com_Port_StringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT] = - { - VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT, /* bLength */ - USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ - /* Product name: "STM32 Virtual COM Port" */ - 'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, ' ', 0, 'V', 0, 'i', 0, - 'r', 0, 't', 0, 'u', 0, 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, - 'M', 0, ' ', 0, 'P', 0, 'o', 0, 'r', 0, 't', 0, ' ', 0, ' ', 0 - }; - -uint8_t Virtual_Com_Port_StringSerial[VIRTUAL_COM_PORT_SIZ_STRING_SERIAL] = - { - VIRTUAL_COM_PORT_SIZ_STRING_SERIAL, /* bLength */ - USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ - 'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, '1', 0, '0', 0 - }; - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_desc.h b/Virtual_COM_Port/usb_desc.h deleted file mode 100644 index df0476a..0000000 --- a/Virtual_COM_Port/usb_desc.h +++ /dev/null @@ -1,53 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_desc.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Descriptor Header for Virtual COM Port Device -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_DESC_H -#define __USB_DESC_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported define -----------------------------------------------------------*/ -#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 -#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 -#define USB_STRING_DESCRIPTOR_TYPE 0x03 -#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 -#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 - -#define VIRTUAL_COM_PORT_DATA_SIZE 64 -#define VIRTUAL_COM_PORT_INT_SIZE 8 - -#define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18 -#define VIRTUAL_COM_PORT_SIZ_CONFIG_DESC 67 -#define VIRTUAL_COM_PORT_SIZ_STRING_LANGID 4 -#define VIRTUAL_COM_PORT_SIZ_STRING_VENDOR 38 -#define VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT 50 -#define VIRTUAL_COM_PORT_SIZ_STRING_SERIAL 26 - -#define STANDARD_ENDPOINT_DESC_SIZE 0x09 - -/* Exported functions ------------------------------------------------------- */ -extern const uint8_t Virtual_Com_Port_DeviceDescriptor[VIRTUAL_COM_PORT_SIZ_DEVICE_DESC]; -extern const uint8_t Virtual_Com_Port_ConfigDescriptor[VIRTUAL_COM_PORT_SIZ_CONFIG_DESC]; - -extern const uint8_t Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID]; -extern const uint8_t Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR]; -extern const uint8_t Virtual_Com_Port_StringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT]; -extern uint8_t Virtual_Com_Port_StringSerial[VIRTUAL_COM_PORT_SIZ_STRING_SERIAL]; - -#endif /* __USB_DESC_H */ -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_endp.c b/Virtual_COM_Port/usb_endp.c deleted file mode 100644 index a633a24..0000000 --- a/Virtual_COM_Port/usb_endp.c +++ /dev/null @@ -1,67 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_endp.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Endpoint routines -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -#include "usb_desc.h" -#include "usb_mem.h" -#include "hw_config.h" -#include "usb_istr.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -uint8_t buffer_out[VIRTUAL_COM_PORT_DATA_SIZE]; -uint8_t buffer_in[VIRTUAL_COM_PORT_DATA_SIZE]; - -__IO uint32_t count_out = 0; -uint32_t count_in = 0; - -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : EP1_IN_Callback -* Description : -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void EP3_IN_Callback(void) -{ - count_in = 0; -} - -/******************************************************************************* -* Function Name : EP3_IN_Callback -* Description : -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void EP5_OUT_Callback(void) -{ - /* Get the received data buffer and update the counter */ - count_out = USB_SIL_Read(EP5_OUT, buffer_out); - -#ifndef STM32F10X_CL - /* Enable the receive of data on EP3 */ - SetEPRxValid(ENDP3); -#endif /* STM32F10X_CL */ -} - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - diff --git a/Virtual_COM_Port/usb_istr.c b/Virtual_COM_Port/usb_istr.c deleted file mode 100644 index c07c964..0000000 --- a/Virtual_COM_Port/usb_istr.c +++ /dev/null @@ -1,419 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_istr.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : ISTR events interrupt service routines -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -#include "usb_prop.h" -#include "usb_pwr.h" -#include "usb_istr.h" - -/* function prototypes Automatically built defining related macros */ -void NOP_Proc(void) { -} - -#define WEAK __attribute__ ((weak)) -void WEAK EP1_IN_Callback(void); -void WEAK EP2_IN_Callback(void); -void WEAK EP3_IN_Callback(void); -void WEAK EP4_IN_Callback(void); -void WEAK EP5_IN_Callback(void); -void WEAK EP6_IN_Callback(void); -void WEAK EP7_IN_Callback(void); - -void WEAK EP1_OUT_Callback(void); -void WEAK EP2_OUT_Callback(void); -void WEAK EP3_OUT_Callback(void); -void WEAK EP4_OUT_Callback(void); -void WEAK EP5_OUT_Callback(void); -void WEAK EP6_OUT_Callback(void); -void WEAK EP7_OUT_Callback(void); - -#pragma weak EP1_IN_Callback = NOP_Proc -#pragma weak EP2_IN_Callback = NOP_Proc -#pragma weak EP3_IN_Callback = NOP_Proc -#pragma weak EP4_IN_Callback = NOP_Proc -#pragma weak EP5_IN_Callback = NOP_Proc -#pragma weak EP6_IN_Callback = NOP_Proc -#pragma weak EP7_IN_Callback = NOP_Proc - -#pragma weak EP1_OUT_Callback = NOP_Proc -#pragma weak EP2_OUT_Callback = NOP_Proc -#pragma weak EP3_OUT_Callback = NOP_Proc -#pragma weak EP4_OUT_Callback = NOP_Proc -#pragma weak EP5_OUT_Callback = NOP_Proc -#pragma weak EP6_OUT_Callback = NOP_Proc -#pragma weak EP7_OUT_Callback = NOP_Proc - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -__IO uint16_t wIstr; /* ISTR register last read value */ -__IO uint8_t bIntPackSOF = 0; /* SOFs received between 2 consecutive packets */ - -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ -/* function pointers to non-control endpoints service routines */ -void (*const pEpInt_IN[7])(void) = - { - EP1_IN_Callback, - EP2_IN_Callback, - EP3_IN_Callback, - EP4_IN_Callback, - EP5_IN_Callback, - EP6_IN_Callback, - EP7_IN_Callback, - }; - -void (*const pEpInt_OUT[7])(void) = - { - EP1_OUT_Callback, - EP2_OUT_Callback, - EP3_OUT_Callback, - EP4_OUT_Callback, - EP5_OUT_Callback, - EP6_OUT_Callback, - EP7_OUT_Callback, - }; - -#ifndef STM32F10X_CL - -/******************************************************************************* -* Function Name : USB_Istr -* Description : STR events interrupt service routine -* Input : -* Output : -* Return : -*******************************************************************************/ -void USB_Istr(void) -{ - - wIstr = _GetISTR(); - -#if (IMR_MSK & ISTR_CTR) - if (wIstr & ISTR_CTR & wInterrupt_Mask) - { - /* servicing of the endpoint correct transfer interrupt */ - /* clear of the CTR flag into the sub */ - CTR_LP(); -#ifdef CTR_CALLBACK - CTR_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_RESET) - if (wIstr & ISTR_RESET & wInterrupt_Mask) - { - _SetISTR((uint16_t)CLR_RESET); - Device_Property.Reset(); -#ifdef RESET_CALLBACK - RESET_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_DOVR) - if (wIstr & ISTR_DOVR & wInterrupt_Mask) - { - _SetISTR((uint16_t)CLR_DOVR); -#ifdef DOVR_CALLBACK - DOVR_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_ERR) - if (wIstr & ISTR_ERR & wInterrupt_Mask) - { - _SetISTR((uint16_t)CLR_ERR); -#ifdef ERR_CALLBACK - ERR_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_WKUP) - if (wIstr & ISTR_WKUP & wInterrupt_Mask) - { - _SetISTR((uint16_t)CLR_WKUP); - Resume(RESUME_EXTERNAL); -#ifdef WKUP_CALLBACK - WKUP_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_SUSP) - if (wIstr & ISTR_SUSP & wInterrupt_Mask) - { - - /* check if SUSPEND is possible */ - if (fSuspendEnabled) - { - Suspend(); - } - else - { - /* if not possible then resume after xx ms */ - Resume(RESUME_LATER); - } - /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - _SetISTR((uint16_t)CLR_SUSP); -#ifdef SUSP_CALLBACK - SUSP_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_SOF) - if (wIstr & ISTR_SOF & wInterrupt_Mask) - { - _SetISTR((uint16_t)CLR_SOF); - bIntPackSOF++; - -#ifdef SOF_CALLBACK - SOF_Callback(); -#endif - } -#endif - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#if (IMR_MSK & ISTR_ESOF) - if (wIstr & ISTR_ESOF & wInterrupt_Mask) - { - _SetISTR((uint16_t)CLR_ESOF); - /* resume handling timing is made with ESOFs */ - Resume(RESUME_ESOF); /* request without change of the machine state */ - -#ifdef ESOF_CALLBACK - ESOF_Callback(); -#endif - } -#endif -} /* USB_Istr */ - -/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ -#else /* STM32F10X_CL */ - - -/******************************************************************************* -* Function Name : STM32_PCD_OTG_ISR_Handler -* Description : Handles all USB Device Interrupts -* Input : None -* Output : None -* Return : status -*******************************************************************************/ -u32 STM32_PCD_OTG_ISR_Handler (void) -{ - USB_OTG_int_sts_data gintr_status; - u32 retval = 0; - - if (IsDeviceMode()) /* ensure that we are in device mode */ - { - gintr_status.d32 = OTGD_FS_ReadCoreItr(); - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - - /* If there is no interrupt pending exit the interrupt routine */ - if (!gintr_status.d32) - { - return 0; - } - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Early Suspend interrupt */ -#ifdef INTR_ERLYSUSPEND - if (gintr_status.b.erlysuspend) - { - retval |= OTGD_FS_Handle_EarlySuspend_ISR(); - } -#endif /* INTR_ERLYSUSPEND */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* End of Periodic Frame interrupt */ -#ifdef INTR_EOPFRAME - if (gintr_status.b.eopframe) - { - retval |= OTGD_FS_Handle_EOPF_ISR(); - } -#endif /* INTR_EOPFRAME */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Non Periodic Tx FIFO Emty interrupt */ -#ifdef INTR_NPTXFEMPTY - if (gintr_status.b.nptxfempty) - { - retval |= OTGD_FS_Handle_NPTxFE_ISR(); - } -#endif /* INTR_NPTXFEMPTY */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Wakeup or RemoteWakeup interrupt */ -#ifdef INTR_WKUPINTR - if (gintr_status.b.wkupintr) - { - retval |= OTGD_FS_Handle_Wakeup_ISR(); - } -#endif /* INTR_WKUPINTR */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Suspend interrupt */ -#ifdef INTR_USBSUSPEND - if (gintr_status.b.usbsuspend) - { - /* check if SUSPEND is possible */ - if (fSuspendEnabled) - { - Suspend(); - } - else - { - /* if not possible then resume after xx ms */ - Resume(RESUME_LATER); /* This case shouldn't happen in OTG Device mode because - there's no ESOF interrupt to increment the ResumeS.bESOFcnt in the Resume state machine */ - } - - retval |= OTGD_FS_Handle_USBSuspend_ISR(); - } -#endif /* INTR_USBSUSPEND */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Start of Frame interrupt */ -#ifdef INTR_SOFINTR - if (gintr_status.b.sofintr) - { - /* Update the frame number variable */ - bIntPackSOF++; - - retval |= OTGD_FS_Handle_Sof_ISR(); - } -#endif /* INTR_SOFINTR */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Receive FIFO Queue Status Level interrupt */ -#ifdef INTR_RXSTSQLVL - if (gintr_status.b.rxstsqlvl) - { - retval |= OTGD_FS_Handle_RxStatusQueueLevel_ISR(); - } -#endif /* INTR_RXSTSQLVL */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Enumeration Done interrupt */ -#ifdef INTR_ENUMDONE - if (gintr_status.b.enumdone) - { - retval |= OTGD_FS_Handle_EnumDone_ISR(); - } -#endif /* INTR_ENUMDONE */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Reset interrutp */ -#ifdef INTR_USBRESET - if (gintr_status.b.usbreset) - { - retval |= OTGD_FS_Handle_UsbReset_ISR(); - } -#endif /* INTR_USBRESET */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* IN Endpoint interrupt */ -#ifdef INTR_INEPINTR - if (gintr_status.b.inepint) - { - retval |= OTGD_FS_Handle_InEP_ISR(); - } -#endif /* INTR_INEPINTR */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* OUT Endpoint interrupt */ -#ifdef INTR_OUTEPINTR - if (gintr_status.b.outepintr) - { - retval |= OTGD_FS_Handle_OutEP_ISR(); - } -#endif /* INTR_OUTEPINTR */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Mode Mismatch interrupt */ -#ifdef INTR_MODEMISMATCH - if (gintr_status.b.modemismatch) - { - retval |= OTGD_FS_Handle_ModeMismatch_ISR(); - } -#endif /* INTR_MODEMISMATCH */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Global IN Endpoints NAK Effective interrupt */ -#ifdef INTR_GINNAKEFF - if (gintr_status.b.ginnakeff) - { - retval |= OTGD_FS_Handle_GInNakEff_ISR(); - } -#endif /* INTR_GINNAKEFF */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Global OUT Endpoints NAK effective interrupt */ -#ifdef INTR_GOUTNAKEFF - if (gintr_status.b.goutnakeff) - { - retval |= OTGD_FS_Handle_GOutNakEff_ISR(); - } -#endif /* INTR_GOUTNAKEFF */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Isochrounous Out packet Dropped interrupt */ -#ifdef INTR_ISOOUTDROP - if (gintr_status.b.isooutdrop) - { - retval |= OTGD_FS_Handle_IsoOutDrop_ISR(); - } -#endif /* INTR_ISOOUTDROP */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Endpoint Mismatch error interrupt */ -#ifdef INTR_EPMISMATCH - if (gintr_status.b.epmismatch) - { - retval |= OTGD_FS_Handle_EPMismatch_ISR(); - } -#endif /* INTR_EPMISMATCH */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Incomplete Isochrous IN tranfer error interrupt */ -#ifdef INTR_INCOMPLISOIN - if (gintr_status.b.incomplisoin) - { - retval |= OTGD_FS_Handle_IncomplIsoIn_ISR(); - } -#endif /* INTR_INCOMPLISOIN */ - - /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ - /* Incomplete Isochrous OUT tranfer error interrupt */ -#ifdef INTR_INCOMPLISOOUT - if (gintr_status.b.outepintr) - { - retval |= OTGD_FS_Handle_IncomplIsoOut_ISR(); - } -#endif /* INTR_INCOMPLISOOUT */ - - } - return retval; -} - -#endif /* STM32F10X_CL */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_istr.h b/Virtual_COM_Port/usb_istr.h deleted file mode 100644 index 77698f6..0000000 --- a/Virtual_COM_Port/usb_istr.h +++ /dev/null @@ -1,104 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_istr.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : This file includes the peripherals header files in the -* user application. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_ISTR_H -#define __USB_ISTR_H - -/* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ - -#ifndef STM32F10X_CL - void USB_Istr(void); -#else /* STM32F10X_CL */ - u32 STM32_PCD_OTG_ISR_Handler(void); -#endif /* STM32F10X_CL */ - - -#ifndef STM32F10X_CL - -#ifdef CTR_CALLBACK -void CTR_Callback(void); -#endif - -#ifdef DOVR_CALLBACK -void DOVR_Callback(void); -#endif - -#ifdef ERR_CALLBACK -void ERR_Callback(void); -#endif - -#ifdef WKUP_CALLBACK -void WKUP_Callback(void); -#endif - -#ifdef SUSP_CALLBACK -void SUSP_Callback(void); -#endif - -#ifdef RESET_CALLBACK -void RESET_Callback(void); -#endif - -#ifdef SOF_CALLBACK -void SOF_Callback(void); -#endif - -#ifdef ESOF_CALLBACK -void ESOF_Callback(void); -#endif - -#else /* STM32F10X_CL */ - -/* Interrupt subroutines user callbacks prototypes. - These callbacks are called into the respective interrupt sunroutine functinos - and can be tailored for various user application purposes. - Note: Make sure that the correspondant interrupt is enabled through the - definition in usb_conf.h file */ -void INTR_MODEMISMATCH_Callback(void); -void INTR_SOFINTR_Callback(void); -void INTR_RXSTSQLVL_Callback(void); -void INTR_NPTXFEMPTY_Callback(void); -void INTR_GINNAKEFF_Callback(void); -void INTR_GOUTNAKEFF_Callback(void); -void INTR_ERLYSUSPEND_Callback(void); -void INTR_USBSUSPEND_Callback(void); -void INTR_USBRESET_Callback(void); -void INTR_ENUMDONE_Callback(void); -void INTR_ISOOUTDROP_Callback(void); -void INTR_EOPFRAME_Callback(void); -void INTR_EPMISMATCH_Callback(void); -void INTR_INEPINTR_Callback(void); -void INTR_OUTEPINTR_Callback(void); -void INTR_INCOMPLISOIN_Callback(void); -void INTR_INCOMPLISOOUT_Callback(void); -void INTR_WKUPINTR_Callback(void); - -/* Isochronous data update */ -void INTR_RXSTSQLVL_ISODU_Callback(void); - -#endif /* STM32F10X_CL */ - - -#endif /*__USB_ISTR_H*/ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_prop.c b/Virtual_COM_Port/usb_prop.c deleted file mode 100644 index 0f6d85b..0000000 --- a/Virtual_COM_Port/usb_prop.c +++ /dev/null @@ -1,419 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_prop.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : All processing related to Virtual Com Port Demo -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "usb_lib.h" -#include "usb_conf.h" -#include "usb_prop.h" -#include "usb_desc.h" -#include "usb_pwr.h" -#include "hw_config.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -uint8_t Request = 0; - -LINE_CODING linecoding = - { - 115200, /* baud rate*/ - 0x00, /* stop bits-1*/ - 0x00, /* parity - none*/ - 0x08 /* no. of bits 8*/ - }; - -/* -------------------------------------------------------------------------- */ -/* Structures initializations */ -/* -------------------------------------------------------------------------- */ - -DEVICE Device_Table = - { - EP_NUM, - 1 - }; - -DEVICE_PROP Device_Property = - { - Virtual_Com_Port_init, - Virtual_Com_Port_Reset, - Virtual_Com_Port_Status_In, - Virtual_Com_Port_Status_Out, - Virtual_Com_Port_Data_Setup, - Virtual_Com_Port_NoData_Setup, - Virtual_Com_Port_Get_Interface_Setting, - Virtual_Com_Port_GetDeviceDescriptor, - Virtual_Com_Port_GetConfigDescriptor, - Virtual_Com_Port_GetStringDescriptor, - 0, - 0x40 /*MAX PACKET SIZE*/ - }; - -USER_STANDARD_REQUESTS User_Standard_Requests = - { - Virtual_Com_Port_GetConfiguration, - Virtual_Com_Port_SetConfiguration, - Virtual_Com_Port_GetInterface, - Virtual_Com_Port_SetInterface, - Virtual_Com_Port_GetStatus, - Virtual_Com_Port_ClearFeature, - Virtual_Com_Port_SetEndPointFeature, - Virtual_Com_Port_SetDeviceFeature, - Virtual_Com_Port_SetDeviceAddress - }; - -ONE_DESCRIPTOR Device_Descriptor = - { - (uint8_t*)Virtual_Com_Port_DeviceDescriptor, - VIRTUAL_COM_PORT_SIZ_DEVICE_DESC - }; - -ONE_DESCRIPTOR Config_Descriptor = - { - (uint8_t*)Virtual_Com_Port_ConfigDescriptor, - VIRTUAL_COM_PORT_SIZ_CONFIG_DESC - }; - -ONE_DESCRIPTOR String_Descriptor[4] = - { - {(uint8_t*)Virtual_Com_Port_StringLangID, VIRTUAL_COM_PORT_SIZ_STRING_LANGID}, - {(uint8_t*)Virtual_Com_Port_StringVendor, VIRTUAL_COM_PORT_SIZ_STRING_VENDOR}, - {(uint8_t*)Virtual_Com_Port_StringProduct, VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT}, - {(uint8_t*)Virtual_Com_Port_StringSerial, VIRTUAL_COM_PORT_SIZ_STRING_SERIAL} - }; - -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Extern function prototypes ------------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ -/******************************************************************************* -* Function Name : Virtual_Com_Port_init. -* Description : Virtual COM Port Mouse init routine. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Virtual_Com_Port_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(); - - /* configure the USART to the default settings */ - //USART_Config_Default(); - - bDeviceState = UNCONNECTED; -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_Reset -* Description : Virtual_Com_Port Mouse reset routine -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Virtual_Com_Port_Reset(void) -{ - /* Set Virtual_Com_Port DEVICE as not configured */ - pInformation->Current_Configuration = 0; - - /* Current Feature initialization */ - pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7]; - - /* Set Virtual_Com_Port DEVICE with the default Interface*/ - pInformation->Current_Interface = 0; - -#ifdef STM32F10X_CL - /* EP0 is already configured by USB_SIL_Init() function */ - - /* Init EP1 IN as Bulk endpoint */ - OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_BULK, VIRTUAL_COM_PORT_DATA_SIZE); - - /* Init EP2 IN as Interrupt endpoint */ - OTG_DEV_EP_Init(EP2_IN, OTG_DEV_EP_TYPE_INT, VIRTUAL_COM_PORT_INT_SIZE); - - /* Init EP3 OUT as Bulk endpoint */ - OTG_DEV_EP_Init(EP3_OUT, OTG_DEV_EP_TYPE_BULK, VIRTUAL_COM_PORT_DATA_SIZE); -#else - - 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, Device_Property.MaxPacketSize); - 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); - - /* Set this device to response on default address */ - SetDeviceAddress(0); -#endif /* STM32F10X_CL */ - - bDeviceState = ATTACHED; -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_SetConfiguration. -* Description : Udpade the device state to configured. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Virtual_Com_Port_SetConfiguration(void) -{ - DEVICE_INFO *pInfo = &Device_Info; - - if (pInfo->Current_Configuration != 0) - { - /* Device configured */ - bDeviceState = CONFIGURED; - } -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_SetConfiguration. -* Description : Udpade the device state to addressed. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Virtual_Com_Port_SetDeviceAddress (void) -{ - bDeviceState = ADDRESSED; -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_Status_In. -* Description : Virtual COM Port Status In Routine. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Virtual_Com_Port_Status_In(void) -{ - if (Request == SET_LINE_CODING) - { - //USART_Config(); - Request = 0; - } -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_Status_Out -* Description : Virtual COM Port Status OUT Routine. -* Input : None. -* Output : None. -* Return : None. -*******************************************************************************/ -void Virtual_Com_Port_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. -*******************************************************************************/ -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; - } - Request = SET_LINE_CODING; - } - - 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. -*******************************************************************************/ -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; -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_GetDeviceDescriptor. -* Description : Gets the device descriptor. -* Input : Length. -* Output : None. -* Return : The address of the device descriptor. -*******************************************************************************/ -uint8_t *Virtual_Com_Port_GetDeviceDescriptor(uint16_t Length) -{ - return Standard_GetDescriptorData(Length, &Device_Descriptor); -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_GetConfigDescriptor. -* Description : get the configuration descriptor. -* Input : Length. -* Output : None. -* Return : The address of the configuration descriptor. -*******************************************************************************/ -uint8_t *Virtual_Com_Port_GetConfigDescriptor(uint16_t Length) -{ - return Standard_GetDescriptorData(Length, &Config_Descriptor); -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_GetStringDescriptor -* Description : Gets the string descriptors according to the needed index -* Input : Length. -* Output : None. -* Return : The address of the string descriptors. -*******************************************************************************/ -uint8_t *Virtual_Com_Port_GetStringDescriptor(uint16_t Length) -{ - uint8_t wValue0 = pInformation->USBwValue0; - if (wValue0 > 4) - { - return NULL; - } - else - { - return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]); - } -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_Get_Interface_Setting. -* Description : test the interface and the alternate setting according to the -* supported one. -* Input1 : uint8_t: Interface : interface number. -* Input2 : uint8_t: AlternateSetting : Alternate Setting number. -* Output : None. -* Return : The address of the string descriptors. -*******************************************************************************/ -RESULT Virtual_Com_Port_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; -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_GetLineCoding. -* Description : send the linecoding structure to the PC host. -* Input : Length. -* Output : None. -* Return : Inecoding structure base address. -*******************************************************************************/ -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; -} - -/******************************************************************************* -* Function Name : Virtual_Com_Port_SetLineCoding. -* Description : Set the linecoding structure fields. -* Input : Length. -* Output : None. -* Return : Linecoding structure base address. -*******************************************************************************/ -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; -} - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - diff --git a/Virtual_COM_Port/usb_prop.h b/Virtual_COM_Port/usb_prop.h deleted file mode 100644 index 3adf76b..0000000 --- a/Virtual_COM_Port/usb_prop.h +++ /dev/null @@ -1,74 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_prop.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : All processing related to Virtual COM Port Demo (Endpoint 0) -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __usb_prop_H -#define __usb_prop_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef struct -{ - uint32_t bitrate; - uint8_t format; - uint8_t paritytype; - uint8_t datatype; -}LINE_CODING; - -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported define -----------------------------------------------------------*/ - -#define Virtual_Com_Port_GetConfiguration NOP_Process -//#define Virtual_Com_Port_SetConfiguration NOP_Process -#define Virtual_Com_Port_GetInterface NOP_Process -#define Virtual_Com_Port_SetInterface NOP_Process -#define Virtual_Com_Port_GetStatus NOP_Process -#define Virtual_Com_Port_ClearFeature NOP_Process -#define Virtual_Com_Port_SetEndPointFeature NOP_Process -#define Virtual_Com_Port_SetDeviceFeature NOP_Process -//#define Virtual_Com_Port_SetDeviceAddress NOP_Process - -#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 - -/* Exported functions ------------------------------------------------------- */ -void Virtual_Com_Port_init(void); -void Virtual_Com_Port_Reset(void); -void Virtual_Com_Port_SetConfiguration(void); -void Virtual_Com_Port_SetDeviceAddress (void); -void Virtual_Com_Port_Status_In (void); -void Virtual_Com_Port_Status_Out (void); -RESULT Virtual_Com_Port_Data_Setup(uint8_t); -RESULT Virtual_Com_Port_NoData_Setup(uint8_t); -RESULT Virtual_Com_Port_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting); -uint8_t *Virtual_Com_Port_GetDeviceDescriptor(uint16_t ); -uint8_t *Virtual_Com_Port_GetConfigDescriptor(uint16_t); -uint8_t *Virtual_Com_Port_GetStringDescriptor(uint16_t); - -uint8_t *Virtual_Com_Port_GetLineCoding(uint16_t Length); -uint8_t *Virtual_Com_Port_SetLineCoding(uint16_t Length); - -#endif /* __usb_prop_H */ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ - diff --git a/Virtual_COM_Port/usb_pwr.c b/Virtual_COM_Port/usb_pwr.c deleted file mode 100644 index 1346779..0000000 --- a/Virtual_COM_Port/usb_pwr.c +++ /dev/null @@ -1,251 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_pwr.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Connection/disconnection & power management -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x.h" -#include "usb_lib.h" -#include "usb_conf.h" -#include "usb_pwr.h" -#include "hw_config.h" - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -__IO uint32_t bDeviceState = UNCONNECTED; /* USB device status */ -__IO bool fSuspendEnabled = TRUE; /* true when suspend is possible */ - -struct -{ - __IO RESUME_STATE eState; - __IO uint8_t bESOFcnt; -}ResumeS; - -/* Extern variables ----------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Extern function prototypes ------------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : PowerOn -* Description : -* Input : None. -* Output : None. -* Return : USB_SUCCESS. -*******************************************************************************/ -RESULT PowerOn(void) -{ -#ifndef STM32F10X_CL - uint16_t wRegVal; - - /*** cable plugged-in ? ***/ - USB_Cable_Config(ENABLE); - - /*** CNTR_PWDN = 0 ***/ - wRegVal = CNTR_FRES; - _SetCNTR(wRegVal); - - /*** CNTR_FRES = 0 ***/ - wInterrupt_Mask = 0; - _SetCNTR(wInterrupt_Mask); - /*** Clear pending interrupts ***/ - _SetISTR(0); - /*** Set interrupt mask ***/ - wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; - _SetCNTR(wInterrupt_Mask); -#endif /* STM32F10X_CL */ - - return USB_SUCCESS; -} - -/******************************************************************************* -* Function Name : PowerOff -* Description : handles switch-off conditions -* Input : None. -* Output : None. -* Return : USB_SUCCESS. -*******************************************************************************/ -RESULT PowerOff() -{ -#ifndef STM32F10X_CL - /* disable all ints and force USB reset */ - _SetCNTR(CNTR_FRES); - /* clear interrupt status register */ - _SetISTR(0); - /* Disable the Pull-Up*/ - USB_Cable_Config(DISABLE); - /* switch-off device */ - _SetCNTR(CNTR_FRES + CNTR_PDWN); -#endif /* STM32F10X_CL */ - - /* sw variables reset */ - /* ... */ - - return USB_SUCCESS; -} - -/******************************************************************************* -* Function Name : Suspend -* Description : sets suspend mode operating conditions -* Input : None. -* Output : None. -* Return : USB_SUCCESS. -*******************************************************************************/ -void Suspend(void) -{ -#ifndef STM32F10X_CL - uint16_t wCNTR; - /* suspend preparation */ - /* ... */ - - /* macrocell enters suspend mode */ - wCNTR = _GetCNTR(); - wCNTR |= CNTR_FSUSP; - _SetCNTR(wCNTR); -#endif /* STM32F10X_CL */ - - /* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */ - /* power reduction */ - /* ... on connected devices */ - -#ifndef STM32F10X_CL - /* force low-power mode in the macrocell */ - wCNTR = _GetCNTR(); - wCNTR |= CNTR_LPMODE; - _SetCNTR(wCNTR); -#endif /* STM32F10X_CL */ - - /* switch-off the clocks */ - /* ... */ - Enter_LowPowerMode(); - -} - -/******************************************************************************* -* Function Name : Resume_Init -* Description : Handles wake-up restoring normal operations -* Input : None. -* Output : None. -* Return : USB_SUCCESS. -*******************************************************************************/ -void Resume_Init(void) -{ -#ifndef STM32F10X_CL - uint16_t wCNTR; -#endif /* STM32F10X_CL */ - - /* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */ - /* restart the clocks */ - /* ... */ - -#ifndef STM32F10X_CL - /* CNTR_LPMODE = 0 */ - wCNTR = _GetCNTR(); - wCNTR &= (~CNTR_LPMODE); - _SetCNTR(wCNTR); -#endif /* STM32F10X_CL */ - - /* restore full power */ - /* ... on connected devices */ - Leave_LowPowerMode(); - -#ifndef STM32F10X_CL - /* reset FSUSP bit */ - _SetCNTR(IMR_MSK); -#endif /* STM32F10X_CL */ - - /* reverse suspend preparation */ - /* ... */ - -} - -/******************************************************************************* -* Function Name : Resume -* Description : This is the state machine handling resume operations and -* timing sequence. The control is based on the Resume structure -* variables and on the ESOF interrupt calling this subroutine -* without changing machine state. -* Input : a state machine value (RESUME_STATE) -* RESUME_ESOF doesn't change ResumeS.eState allowing -* decrementing of the ESOF counter in different states. -* Output : None. -* Return : None. -*******************************************************************************/ -void Resume(RESUME_STATE eResumeSetVal) -{ -#ifndef STM32F10X_CL - uint16_t wCNTR; -#endif /* STM32F10X_CL */ - - if (eResumeSetVal != RESUME_ESOF) - ResumeS.eState = eResumeSetVal; - - switch (ResumeS.eState) - { - case RESUME_EXTERNAL: - Resume_Init(); - ResumeS.eState = RESUME_OFF; - break; - case RESUME_INTERNAL: - Resume_Init(); - ResumeS.eState = RESUME_START; - break; - case RESUME_LATER: - ResumeS.bESOFcnt = 2; - ResumeS.eState = RESUME_WAIT; - break; - case RESUME_WAIT: - ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) - ResumeS.eState = RESUME_START; - break; - case RESUME_START: - #ifdef STM32F10X_CL - OTGD_FS_Dev_SetRemoteWakeup(); - #else - wCNTR = _GetCNTR(); - wCNTR |= CNTR_RESUME; - _SetCNTR(wCNTR); - #endif /* STM32F10X_CL */ - ResumeS.eState = RESUME_ON; - ResumeS.bESOFcnt = 10; - break; - case RESUME_ON: - #ifndef STM32F10X_CL - ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) - { - #endif /* STM32F10X_CL */ - #ifdef STM32F10X_CL - OTGD_FS_Dev_ResetRemoteWakeup(); - #else - wCNTR = _GetCNTR(); - wCNTR &= (~CNTR_RESUME); - _SetCNTR(wCNTR); - #endif /* STM32F10X_CL */ - ResumeS.eState = RESUME_OFF; - #ifndef STM32F10X_CL - } - #endif /* STM32F10X_CL */ - break; - case RESUME_OFF: - case RESUME_ESOF: - default: - ResumeS.eState = RESUME_OFF; - break; - } -} - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/Virtual_COM_Port/usb_pwr.h b/Virtual_COM_Port/usb_pwr.h deleted file mode 100644 index 21a9927..0000000 --- a/Virtual_COM_Port/usb_pwr.h +++ /dev/null @@ -1,59 +0,0 @@ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_pwr.h -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : Connection/disconnection & power management header -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USB_PWR_H -#define __USB_PWR_H - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -typedef enum _RESUME_STATE -{ - RESUME_EXTERNAL, - RESUME_INTERNAL, - RESUME_LATER, - RESUME_WAIT, - RESUME_START, - RESUME_ON, - RESUME_OFF, - RESUME_ESOF -} RESUME_STATE; - -typedef enum _DEVICE_STATE -{ - UNCONNECTED, - ATTACHED, - POWERED, - SUSPENDED, - ADDRESSED, - CONFIGURED -} DEVICE_STATE; - -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ -void Suspend(void); -void Resume_Init(void); -void Resume(RESUME_STATE eResumeSetVal); -RESULT PowerOn(void); -RESULT PowerOff(void); - -/* External variables --------------------------------------------------------*/ -extern __IO uint32_t bDeviceState; /* USB device status */ -extern __IO bool fSuspendEnabled; /* true when suspend is possible */ - -#endif /*__USB_PWR_H*/ - -/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/boards/CQ_STARM/board.c b/boards/CQ_STARM/board.c index cd2a779..c079a0c 100644 --- a/boards/CQ_STARM/board.c +++ b/boards/CQ_STARM/board.c @@ -4,34 +4,8 @@ #include "../common/hwinit.c" -void -hwinit0 (void) -{ - hwinit0_common (); -} - void hwinit1 (void) { hwinit1_common (); } - -void -USB_Cable_Config (FunctionalState NewState) -{ - /* CQ STARM has no functionality to stop USB. */ - /* - * It seems that users can add the functionality with USB_DC (PD9) - * though - */ - (void)NewState; -} - -void -set_led (int value) -{ - if (value) - palSetPad (IOPORT3, GPIOC_LED); - else - palClearPad (IOPORT3, GPIOC_LED); -} diff --git a/boards/CQ_STARM/board.h b/boards/CQ_STARM/board.h index 9d001d2..5268912 100644 --- a/boards/CQ_STARM/board.h +++ b/boards/CQ_STARM/board.h @@ -30,6 +30,10 @@ /* * Setup for the CQ STARM board. */ +#undef SET_USB_CONDITION /* No functionality to disconnect USB */ +#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */ +#define GPIO_LED GPIOC_LED +#define IOPORT_LED GPIOC /* * Board identifier. diff --git a/boards/FST_01/board.c b/boards/FST_01/board.c new file mode 100644 index 0000000..7db9dee --- /dev/null +++ b/boards/FST_01/board.c @@ -0,0 +1,83 @@ +#include "config.h" +#include "ch.h" +#include "hal.h" + +#include "../common/hwinit.c" + +void +hwinit1 (void) +{ + hwinit1_common (); + +#if defined(PINPAD_CIR_SUPPORT) + /* PA0/TIM2_CH1 = 1 (pull up) */ + /* PA1/TIM2_CH2 = 0 (pull down) */ + /* PA2/TIM2_CH3 <= Vout of CIR receiver module */ + + /* EXTI2 <= PA2 */ + AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI2_PA; + EXTI->IMR = 0; + EXTI->FTSR = EXTI_FTSR_TR2; + NVICEnableVector(EXTI2_IRQn, + CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY)); + /* TIM2 */ + RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; + RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST; + RCC->APB1RSTR = 0; + NVICEnableVector(TIM2_IRQn, + CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY)); + + TIM2->CR1 = TIM_CR1_URS | TIM_CR1_ARPE; + TIM2->CR2 = TIM_CR2_TI1S; + TIM2->SMCR = TIM_SMCR_TS_0 | TIM_SMCR_TS_2 | TIM_SMCR_SMS_2; + TIM2->DIER = 0; /* Disable interrupt for now */ + TIM2->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_3 + | TIM_CCMR1_CC2S_1 | TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_3; + TIM2->CCMR2 = 0; + TIM2->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P; + TIM2->PSC = 72 - 1; /* 1 MHz */ + TIM2->ARR = 18000; /* 18 ms */ + /* Generate UEV to upload PSC and ARR */ + TIM2->EGR = TIM_EGR_UG; +#endif +} + +#if defined(PINPAD_CIR_SUPPORT) +void +cir_ext_disable (void) +{ + EXTI->PR = EXTI_PR_PR2; + EXTI->IMR &= ~EXTI_IMR_MR2; +} + +void +cir_ext_enable (void) +{ + EXTI->IMR |= EXTI_IMR_MR2; +} + +extern void cir_ext_interrupt (void); +extern void cir_timer_interrupt (void); + +CH_IRQ_HANDLER (EXTI2_IRQHandler) +{ + CH_IRQ_PROLOGUE (); + chSysLockFromIsr (); + + cir_ext_interrupt (); + + chSysUnlockFromIsr (); + CH_IRQ_EPILOGUE (); +} + +CH_IRQ_HANDLER (TIM2_IRQHandler) +{ + CH_IRQ_PROLOGUE(); + chSysLockFromIsr(); + + cir_timer_interrupt (); + + chSysUnlockFromIsr(); + CH_IRQ_EPILOGUE(); +} +#endif diff --git a/boards/FST_01/board.h b/boards/FST_01/board.h new file mode 100644 index 0000000..eafad06 --- /dev/null +++ b/boards/FST_01/board.h @@ -0,0 +1,147 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT 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. + + ChibiOS/RT 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 . + + --- + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes ChibiOS/RT, without being obliged to provide + the source code for any proprietary components. See the file exception.txt + for full details of how and when the exception can be applied. +*/ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for the FST-01 board. + */ +#define SET_USB_CONDITION(en) en /* To connect USB, call palSetPad */ +#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */ +#define GPIO_USB GPIOA_USB_ENABLE +#define IOPORT_USB GPIOA +#define GPIO_LED GPIOB_LED +#define IOPORT_LED GPIOB + +/* + * Board identifier. + */ +#define BOARD_FST_01 +#define BOARD_NAME "FST-01" + +/* + * Board frequencies. + */ +#define STM32_LSECLK 32768 +#define STM32_HSECLK 12000000 + +/* + * MCU type, this macro is used by both the ST library and the ChibiOS/RT + * native STM32 HAL. + */ +#define STM32F10X_MD +#define CPU_WITH_NO_GPIOE 1 + +/* + * IO pins assignments. + */ +#define GPIOB_LED 0 +#define GPIOA_USB_ENABLE 10 +#define GPIOA_SPI1NSS 4 + +/* + * Timer assignment for CIR + */ +#define TIMx TIM2 + +/* + * I/O ports initial setup, this configuration is established soon after reset + * in the initialization code. + * + * The digits have the following meaning: + * 0 - Analog input. + * 1 - Push Pull output 10MHz. + * 2 - Push Pull output 2MHz. + * 3 - Push Pull output 50MHz. + * 4 - Digital input. + * 5 - Open Drain output 10MHz. + * 6 - Open Drain output 2MHz. + * 7 - Open Drain output 50MHz. + * 8 - Digital input with PullUp or PullDown resistor depending on ODR. + * 9 - Alternate Push Pull output 10MHz. + * A - Alternate Push Pull output 2MHz. + * B - Alternate Push Pull output 50MHz. + * C - Reserved. + * D - Alternate Open Drain output 10MHz. + * E - Alternate Open Drain output 2MHz. + * F - Alternate Open Drain output 50MHz. + * Please refer to the STM32 Reference Manual for details. + */ + +/* + * Port A setup. + * PA0 - input with pull-up (TIM2_CH1) + * PA1 - input with pull-down (TIM2_CH2) + * PA2 - input with pull-up (TIM2_CH3) + * PA4 - Push pull output (SPI1_NSS) + * PA5 - Alternate Push pull output (SPI1_SCK) + * PA6 - Alternate Push pull output (SPI1_MISO) + * PA7 - Alternate Push pull output (SPI1_MOSI) + * PA10 - Push pull output (USB 1:ON 0:OFF) + * PA11 - input with pull-up (USBDM) + * PA12 - input with pull-up (USBDP) + */ +#define VAL_GPIOACRL 0xBBB38888 /* PA7...PA0 */ +#define VAL_GPIOACRH 0x88888388 /* PA15...PA8 */ +#define VAL_GPIOAODR 0xFFFFFFFD + +/* + * Port B setup. + * Everything input with pull-up except: + * PB0 - Push pull output (LED 1:ON 0:OFF) + */ +#define VAL_GPIOBCRL 0x88888883 /* PB7...PB0 */ +#define VAL_GPIOBCRH 0x88888888 /* PB15...PB8 */ +#define VAL_GPIOBODR 0xFFFFFFFF + +/* + * Port C setup. + * Everything input with pull-up except: + */ +#define VAL_GPIOCCRL 0x88888888 /* PC7...PC0 */ +#define VAL_GPIOCCRH 0x88888888 /* PC15...PC8 */ +#define VAL_GPIOCODR 0xFFFFFFFF + +/* + * Port D setup. + * Everything input with pull-up except: + * PD0 - Normal input (XTAL). + * PD1 - Normal input (XTAL). + */ +#define VAL_GPIODCRL 0x88888844 /* PD7...PD0 */ +#define VAL_GPIODCRH 0x88888888 /* PD15...PD8 */ +#define VAL_GPIODODR 0xFFFFFFFF + +/* + * Port E setup. + * Everything input with pull-up except: + */ +#define VAL_GPIOECRL 0x88888888 /* PE7...PE0 */ +#define VAL_GPIOECRH 0x88888888 /* PE15...PE8 */ +#define VAL_GPIOEODR 0xFFFFFFFF + +#endif /* _BOARD_H_ */ diff --git a/boards/FST_01/mcuconf.h b/boards/FST_01/mcuconf.h new file mode 100644 index 0000000..56235c0 --- /dev/null +++ b/boards/FST_01/mcuconf.h @@ -0,0 +1,15 @@ +/* + * HAL driver system settings. + */ +#define STM32_SW STM32_SW_PLL +#define STM32_PLLSRC STM32_PLLSRC_HSE +#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1 +#define STM32_PLLMUL_VALUE 6 +#define STM32_HPRE STM32_HPRE_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV2 +#define STM32_PPRE2 STM32_PPRE2_DIV2 +#define STM32_ADCPRE STM32_ADCPRE_DIV4 +#define STM32_USBPRE STM32_USBPRE_DIV1P5 +#define STM32_MCO STM32_MCO_NOCLOCK + +#include "mcuconf-common.h" diff --git a/boards/FST_01_00/board.c b/boards/FST_01_00/board.c new file mode 100644 index 0000000..c079a0c --- /dev/null +++ b/boards/FST_01_00/board.c @@ -0,0 +1,11 @@ +#include "config.h" +#include "ch.h" +#include "hal.h" + +#include "../common/hwinit.c" + +void +hwinit1 (void) +{ + hwinit1_common (); +} diff --git a/boards/FST_01_00/board.h b/boards/FST_01_00/board.h new file mode 100644 index 0000000..5428bcf --- /dev/null +++ b/boards/FST_01_00/board.h @@ -0,0 +1,135 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT 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. + + ChibiOS/RT 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 . + + --- + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes ChibiOS/RT, without being obliged to provide + the source code for any proprietary components. See the file exception.txt + for full details of how and when the exception can be applied. +*/ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for the FST-01 board (experimental version 00). + */ +#define SET_USB_CONDITION(en) en /* To connect USB, call palSetPad */ +#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */ +#define GPIO_USB GPIOA_USB_ENABLE +#define IOPORT_USB GPIOA +#define GPIO_LED GPIOA_LED +#define IOPORT_LED GPIOA + +/* + * Board identifier. + */ +#define BOARD_FST_01 +#define BOARD_NAME "FST-01-00" + +/* + * Board frequencies. + */ +#define STM32_LSECLK 32768 +#define STM32_HSECLK 8000000 + +/* + * MCU type, this macro is used by both the ST library and the ChibiOS/RT + * native STM32 HAL. + */ +#define STM32F10X_MD +#define CPU_WITH_NO_GPIOE 1 + +/* + * IO pins assignments. + */ +#define GPIOA_LED 8 +#define GPIOA_USB_ENABLE 10 + +/* + * I/O ports initial setup, this configuration is established soon after reset + * in the initialization code. + * + * The digits have the following meaning: + * 0 - Analog input. + * 1 - Push Pull output 10MHz. + * 2 - Push Pull output 2MHz. + * 3 - Push Pull output 50MHz. + * 4 - Digital input. + * 5 - Open Drain output 10MHz. + * 6 - Open Drain output 2MHz. + * 7 - Open Drain output 50MHz. + * 8 - Digital input with PullUp or PullDown resistor depending on ODR. + * 9 - Alternate Push Pull output 10MHz. + * A - Alternate Push Pull output 2MHz. + * B - Alternate Push Pull output 50MHz. + * C - Reserved. + * D - Alternate Open Drain output 10MHz. + * E - Alternate Open Drain output 2MHz. + * F - Alternate Open Drain output 50MHz. + * Please refer to the STM32 Reference Manual for details. + */ + +/* + * Port A setup. + * PA11 - input with pull-up (USBDM) + * PA12 - input with pull-up (USBDP) + * Everything input with pull-up except: + * PA8 - Push pull output (LED 1:ON 0:OFF) + * PA10 - Push pull output (USB 1:ON 0:OFF) + */ +#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */ +#define VAL_GPIOACRH 0x88888383 /* PA15...PA8 */ +#define VAL_GPIOAODR 0xFFFFFFFF + +/* + * Port B setup. + * Everything input with pull-up except: + */ +#define VAL_GPIOBCRL 0x88888888 /* PB7...PB0 */ +#define VAL_GPIOBCRH 0x88888888 /* PB15...PB8 */ +#define VAL_GPIOBODR 0xFFFFFFFF + +/* + * Port C setup. + * Everything input with pull-up except: + */ +#define VAL_GPIOCCRL 0x88888888 /* PC7...PC0 */ +#define VAL_GPIOCCRH 0x88888888 /* PC15...PC8 */ +#define VAL_GPIOCODR 0xFFFFFFFF + +/* + * Port D setup. + * Everything input with pull-up except: + * PD0 - Normal input (XTAL). + * PD1 - Normal input (XTAL). + */ +#define VAL_GPIODCRL 0x88888844 /* PD7...PD0 */ +#define VAL_GPIODCRH 0x88888888 /* PD15...PD8 */ +#define VAL_GPIODODR 0xFFFFFFFF + +/* + * Port E setup. + * Everything input with pull-up except: + */ +#define VAL_GPIOECRL 0x88888888 /* PE7...PE0 */ +#define VAL_GPIOECRH 0x88888888 /* PE15...PE8 */ +#define VAL_GPIOEODR 0xFFFFFFFF + +#endif /* _BOARD_H_ */ diff --git a/boards/FST_01_00/mcuconf.h b/boards/FST_01_00/mcuconf.h new file mode 100644 index 0000000..acfb005 --- /dev/null +++ b/boards/FST_01_00/mcuconf.h @@ -0,0 +1,15 @@ +/* + * HAL driver system settings. + */ +#define STM32_SW STM32_SW_PLL +#define STM32_PLLSRC STM32_PLLSRC_HSE +#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1 +#define STM32_PLLMUL_VALUE 9 +#define STM32_HPRE STM32_HPRE_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV2 +#define STM32_PPRE2 STM32_PPRE2_DIV2 +#define STM32_ADCPRE STM32_ADCPRE_DIV4 +#define STM32_USBPRE STM32_USBPRE_DIV1P5 +#define STM32_MCO STM32_MCO_NOCLOCK + +#include "mcuconf-common.h" diff --git a/boards/OLIMEX_STM32_H103/board.c b/boards/OLIMEX_STM32_H103/board.c index 0e22542..c079a0c 100644 --- a/boards/OLIMEX_STM32_H103/board.c +++ b/boards/OLIMEX_STM32_H103/board.c @@ -4,32 +4,8 @@ #include "../common/hwinit.c" -void -hwinit0 (void) -{ - hwinit0_common (); -} - void hwinit1 (void) { hwinit1_common (); } - -void -USB_Cable_Config (FunctionalState NewState) -{ - if (NewState != DISABLE) - palClearPad (IOPORT3, GPIOC_DISC); - else - palSetPad (IOPORT3, GPIOC_DISC); -} - -void -set_led (int value) -{ - if (value) - palClearPad (IOPORT3, GPIOC_LED); - else - palSetPad (IOPORT3, GPIOC_LED); -} diff --git a/boards/OLIMEX_STM32_H103/board.h b/boards/OLIMEX_STM32_H103/board.h index 9554c51..a6c2d84 100644 --- a/boards/OLIMEX_STM32_H103/board.h +++ b/boards/OLIMEX_STM32_H103/board.h @@ -30,6 +30,12 @@ /* * Setup for the Olimex STM32-H103 proto board. */ +#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */ +#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */ +#define GPIO_USB GPIOC_DISC +#define IOPORT_USB GPIOC +#define GPIO_LED GPIOC_LED +#define IOPORT_LED GPIOC /* * Board identifier. diff --git a/boards/STBEE/board.c b/boards/STBEE/board.c index 882d79e..efbbb79 100644 --- a/boards/STBEE/board.c +++ b/boards/STBEE/board.c @@ -4,18 +4,11 @@ #include "../common/hwinit.c" -void -hwinit0 (void) -{ - hwinit0_common (); -} - void hwinit1 (void) { hwinit1_common (); -#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT) /* EXTI0 <= PB0 */ AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB; @@ -69,28 +62,8 @@ hwinit1 (void) /* Generate UEV to upload PSC and ARR */ TIM4->EGR = TIM_EGR_UG; #endif -#endif } -void -USB_Cable_Config (FunctionalState NewState) -{ - if (NewState != DISABLE) - palClearPad (IOPORT4, GPIOD_USB_ENABLE); - else - palSetPad (IOPORT4, GPIOD_USB_ENABLE); -} - -void -set_led (int value) -{ - if (value) - palClearPad (IOPORT4, GPIOD_LED1); - else - palSetPad (IOPORT4, GPIOD_LED1); -} - -#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT) void cir_ext_disable (void) @@ -156,4 +129,3 @@ CH_IRQ_HANDLER (EXTI2_IRQHandler) CH_IRQ_EPILOGUE (); } #endif -#endif diff --git a/boards/STBEE/board.h b/boards/STBEE/board.h index 6e2e74d..75a3f41 100644 --- a/boards/STBEE/board.h +++ b/boards/STBEE/board.h @@ -31,6 +31,12 @@ /* * Setup for the STBee board. */ +#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */ +#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */ +#define GPIO_USB GPIOD_USB_ENABLE +#define IOPORT_USB GPIOD +#define GPIO_LED GPIOD_LED1 +#define IOPORT_LED GPIOD /* * Board identifier. @@ -38,8 +44,12 @@ #define BOARD_STBEE #define BOARD_NAME "STBee" -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT) #define HAVE_7SEGLED 1 +/* + * Timer assignment for CIR + */ +#define TIMx TIM3 #endif /* @@ -85,7 +95,7 @@ * Please refer to the STM32 Reference Manual for details. */ -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT) /* * Port A setup. * PA6 - (TIM3_CH1) input with pull-up diff --git a/boards/STBEE_MINI/board.c b/boards/STBEE_MINI/board.c index edc53f7..c51d347 100644 --- a/boards/STBEE_MINI/board.c +++ b/boards/STBEE_MINI/board.c @@ -4,22 +4,26 @@ #include "../common/hwinit.c" -void -hwinit0 (void) -{ - hwinit0_common (); -} - void hwinit1 (void) { hwinit1_common (); -#if defined(PINPAD_SUPPORT) +#if !defined(DFU_SUPPORT) + if (palReadPad (IOPORT3, GPIOC_BUTTON) == 0) + /* + * Since LEDs are connected to JTMS/SWDIO and JTDI pin, + * we can't use LED to let know users in this state. + */ + for (;;); /* Wait for JTAG debugger connection */ +#endif + +#if defined(PINPAD_SUPPORT) && !defined(DFU_SUPPORT) palWritePort(IOPORT2, 0x7fff); /* Only clear GPIOB_7SEG_DP */ while (palReadPad (IOPORT2, GPIOB_BUTTON) != 0) ; /* Wait for JTAG debugger connection */ palWritePort(IOPORT2, 0xffff); /* All set */ +#endif #if defined(PINPAD_CIR_SUPPORT) /* EXTI0 <= PB0 */ @@ -73,7 +77,6 @@ hwinit1 (void) TIM4->ARR = 31; /* Generate UEV to upload PSC and ARR */ TIM4->EGR = TIM_EGR_UG; -#endif #endif /* * Disable JTAG and SWD, done after hwinit1_common as HAL resets AFIO @@ -83,25 +86,6 @@ hwinit1 (void) palSetPad (IOPORT1, GPIOA_LED2); } -void -USB_Cable_Config (FunctionalState NewState) -{ - if (NewState != DISABLE) - palSetPad (IOPORT1, GPIOA_USB_ENABLE); - else - palClearPad (IOPORT1, GPIOA_USB_ENABLE); -} - -void -set_led (int value) -{ - if (value) - palClearPad (IOPORT1, GPIOA_LED1); - else - palSetPad (IOPORT1, GPIOA_LED1); -} - -#if defined(PINPAD_SUPPORT) #if defined(PINPAD_CIR_SUPPORT) void cir_ext_disable (void) @@ -167,4 +151,3 @@ CH_IRQ_HANDLER (EXTI2_IRQHandler) CH_IRQ_EPILOGUE (); } #endif -#endif diff --git a/boards/STBEE_MINI/board.h b/boards/STBEE_MINI/board.h index 8238c91..da3adae 100644 --- a/boards/STBEE_MINI/board.h +++ b/boards/STBEE_MINI/board.h @@ -31,6 +31,12 @@ /* * Setup for the STBee Mini board. */ +#define SET_USB_CONDITION(en) (en) /* To connect USB, call palSetPad */ +#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */ +#define GPIO_USB GPIOA_USB_ENABLE +#define IOPORT_USB GPIOA +#define GPIO_LED GPIOA_LED1 +#define IOPORT_LED GPIOA /* * Board identifier. @@ -39,8 +45,12 @@ #define BOARD_NAME "STBee Mini" #define CPU_WITH_NO_GPIOE 1 -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT) #define HAVE_7SEGLED 1 +/* + * Timer assignment for CIR + */ +#define TIMx TIM3 #endif /* @@ -88,7 +98,7 @@ * Please refer to the STM32 Reference Manual for details. */ -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DIAL_SUPPORT) /* * Port A setup. * PA6 - (TIM3_CH1) input with pull-up diff --git a/boards/STM32_PRIMER2/board.c b/boards/STM32_PRIMER2/board.c index b75d3eb..83a288b 100644 --- a/boards/STM32_PRIMER2/board.c +++ b/boards/STM32_PRIMER2/board.c @@ -4,12 +4,6 @@ #include "../common/hwinit.c" -void -hwinit0(void) -{ - hwinit0_common (); -} - void hwinit1(void) { @@ -21,21 +15,3 @@ hwinit1(void) palClearPad (IOPORT5, GPIOE_LED); palClearPad (IOPORT3, GPIOC_SHUTDOWN); } - -void -USB_Cable_Config (FunctionalState NewState) -{ - if (NewState != DISABLE) - palClearPad (IOPORT4, GPIOD_DISC); - else - palSetPad (IOPORT4, GPIOD_DISC); -} - -void -set_led (int value) -{ - if (value) - palClearPad (IOPORT5, GPIOE_LEDR); - else - palSetPad (IOPORT5, GPIOE_LEDR); -} diff --git a/boards/STM32_PRIMER2/board.h b/boards/STM32_PRIMER2/board.h index b295095..0991242 100644 --- a/boards/STM32_PRIMER2/board.h +++ b/boards/STM32_PRIMER2/board.h @@ -30,6 +30,12 @@ /* * Setup for the STM32 Primer2. */ +#define SET_USB_CONDITION(en) (!en) /* To connect USB, call palClearPad */ +#define SET_LED_CONDITION(on) (!on) /* To emit light, call palClearPad */ +#define GPIO_USB GPIOD_DISC +#define IOPORT_USB GPIOD +#define GPIO_LED GPIOE_LEDR +#define IOPORT_LED GPIOE /* * Board identifier. diff --git a/boards/STM8S_DISCOVERY/board.c b/boards/STM8S_DISCOVERY/board.c index 88f4032..1fdf2a9 100644 --- a/boards/STM8S_DISCOVERY/board.c +++ b/boards/STM8S_DISCOVERY/board.c @@ -4,18 +4,12 @@ #include "../common/hwinit.c" -void -hwinit0 (void) -{ - hwinit0_common (); -} - void hwinit1 (void) { hwinit1_common (); -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) /* EXTI5 <= PB5 */ AFIO->EXTICR[1] = AFIO_EXTICR2_EXTI5_PB; EXTI->IMR = 0; @@ -46,23 +40,7 @@ hwinit1 (void) AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP; } -void -USB_Cable_Config (FunctionalState NewState) -{ - /* No functionality to stop USB. */ - (void)NewState; -} - -void -set_led (int value) -{ - if (value) - palSetPad (IOPORT1, GPIOA_LED); - else - palClearPad (IOPORT1, GPIOA_LED); -} - -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) void cir_ext_disable (void) { diff --git a/boards/STM8S_DISCOVERY/board.h b/boards/STM8S_DISCOVERY/board.h index e0a2a5e..27b7fce 100644 --- a/boards/STM8S_DISCOVERY/board.h +++ b/boards/STM8S_DISCOVERY/board.h @@ -32,11 +32,16 @@ * Setup for the ST-Link part of STM8S-Discovery board. */ +#undef SET_USB_CONDITION /* No functionality to disconnect USB */ +#define SET_LED_CONDITION(on) on /* To emit light, call palSetPad */ +#define GPIO_LED GPIOA_LED +#define IOPORT_LED GPIOA + /* * Board identifier. */ #define BOARD_ST_DISCOVERY -#define BOARD_NAME "ST-Link" +#define BOARD_NAME "STM8S Discovery" #define CPU_WITH_NO_GPIOE 1 /* @@ -56,6 +61,11 @@ */ #define GPIOA_LED 8 +/* + * Timer assignment for CIR + */ +#define TIMx TIM3 + /* * I/O ports initial setup, this configuration is established soon after reset * in the initialization code. @@ -91,7 +101,7 @@ #define VAL_GPIOACRH 0x88888883 /* PA15...PA8 */ #define VAL_GPIOAODR 0xFFFFFFFF -#if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) /* * Port B setup. * Everything input with pull-up except: diff --git a/boards/common/hw_config.c b/boards/common/hw_config.c deleted file mode 100644 index d355262..0000000 --- a/boards/common/hw_config.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Hardware specific USB functions */ -/* - * For detail, please see the documentation of - * STM32F10x USB Full Speed Device Library (USB-FS-Device_Lib) - * by STMicroelectronics' MCD Application Team - */ - -#include "ch.h" -#include "hal.h" -#include "board.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; -} - -const uint8_t * -unique_device_id (void) -{ - /* STM32F103 has 96-bit unique device identifier */ - const uint8_t *addr = (const uint8_t *)0x1ffff7e8; - - return addr; -} diff --git a/boards/common/hwinit.c b/boards/common/hwinit.c index 648b6aa..e84788e 100644 --- a/boards/common/hwinit.c +++ b/boards/common/hwinit.c @@ -29,15 +29,9 @@ * This initialization is performed just after reset before BSS and DATA * segments initialization. */ -/* - * Common code for hwinit0 - */ -static void hwinit0_common (void) +void +hwinit0 (void) { -#ifdef DFU_SUPPORT - SCB->VTOR = 0x08003000; -#endif - stm32_clock_init(); } diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..14d3b22 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = a4 +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GnukDocumentation.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GnukDocumentation.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/GnukDocumentation" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GnukDocumentation" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/NOTES b/doc/NOTES deleted file mode 100644 index 457ee66..0000000 --- a/doc/NOTES +++ /dev/null @@ -1,46 +0,0 @@ -USB communication -================= - - * No command chaining, but extended APDU and extended Lc and Le. - I think that this keep the code simple. - - * Once in the past (version <= 0.4), the value of - dwMaxCCIDMessageLength was 64 and we supported ICC block chaining, - so that we could not handle multple Bulk transactions. - - * Now, the value of dwMaxCCIDMessageLength is 320, that's the size - of header of ICC block plus size of maximum APDU (by 64 - granularity). Still, some ccid implementation (ccid 1.3.11, for - example) sends ICC block using chaining unfortunately, so we keep - the code of ICC block chaining. - - -OpenPGP card protocol implementation -==================================== - -I try to follow "no clear password(s)" policy, even if it is on -protected flash memory. Futher, keystrings for user and reset code -are removed after key imports. Because of this, replacing keys -are not possible without password information. Thus, replacing -existing keys are not supported. - - -How a private key is stored -=========================== - -KEYPTR - ----> [ P ][ Q ][ N ] - <---encrypted----><--- plain ----> - -key_addr 4-byte -additional_data_encrypted 16-byte -dek_encrypted_by_keystring_pw1 16-byte -dek_encrypted_by_keystring_rc 16-byte -dek_encrypted_by_keystring_pw3 16-byte - -... decrypted to - -[ P ][ Q ] -check 4-byte -random 4-byte -magic[] 8-byte diff --git a/doc/__update_web b/doc/__update_web new file mode 100644 index 0000000..c52612d --- /dev/null +++ b/doc/__update_web @@ -0,0 +1,3 @@ +cd _build +rsync -rntpv html/ atom.fsij.org:/home/fsij/gnuk-doc-html/ +rsync -rtpv html/ atom.fsij.org:/home/fsij/gnuk-doc-html/ diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..fd2eead --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# +# Gnuk Documentation documentation build configuration file, created by +# sphinx-quickstart on Wed Jul 4 15:29:05 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Gnuk Documentation' +copyright = u'2012, NIIBE Yutaka' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'GnukDocumentationdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'GnukDocumentation.tex', u'Gnuk Documentation Documentation', + u'NIIBE Yutaka', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'gnukdocumentation', u'Gnuk Documentation Documentation', + [u'NIIBE Yutaka'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'GnukDocumentation', u'Gnuk Documentation Documentation', + u'NIIBE Yutaka', 'GnukDocumentation', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/development.rst b/doc/development.rst new file mode 100644 index 0000000..065b986 --- /dev/null +++ b/doc/development.rst @@ -0,0 +1,71 @@ +Development Environment +======================= + + +Hardware +-------- + +For development, it is highly recommended to have JTAG/SWD debugger. + +For boards with DFU (Device Firmware Upgrade) feature (such as DfuSe), +it is possible to develop with that. But it should be considered +*experimental* environment, and it should not be used for usual +purpose. That's because it is basically impossible for DfuSe +implementations to disable reading-out from flash ROM. It means +that your secret will be readily extracted by DfuSe. + +For JTAG debugger, Olimex JTAG-Tiny is good and supported well. For +SWD debugger, ST-Link/V2 would be good, and it is supported by +tool/stlinkv2.py. + + +OpenOCD +------- + +For JTAG/SWD debugger, we can use OpenOCD. + +Note that ST-Link/V2 is *not* supported by OpenOCD 0.5.0. It is +supported by version 0.6 or later. + + +GNU Toolchain +------------- + +You need GNU toolchain and newlib for 'arm-none-eabi' target. + +There is "gcc-arm-embedded" project. See: +https://launchpad.net/gcc-arm-embedded/ + +It is based on GCC 4.6. You'd need "-O3 -Os" instead of "-O2" and it +will be slightly better. + +Note that we need to link correct C library (for string functions). +For this purpose, our src/Makefile.in contains following line: + + MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd + +This should not be needed (as -mcpu=cortex-m3 means +-mfix-cortex-m3-ldrd), but it was needed for the configuration of +patch-gcc-config-arm-t-arm-elf.diff in summon-arm-toolchain in practice. + + +Building Gnuk +------------- + +Change directory to ``src``: + + $ cd gnuk-VERSION/src + +Then, run ``configure``: + + $ ./configure --vidpid= + +Here, you need to specify USB vendor ID and product ID. For FSIJ's, +it's: --vidpid=234b:0000 . Please read the section 'USB vendor ID and +product ID' in README. + +Type: + + $ make + +Then, we will have "gnuk.elf". diff --git a/doc/generating-2048-RSA-key.rst b/doc/generating-2048-RSA-key.rst new file mode 100644 index 0000000..3164c54 --- /dev/null +++ b/doc/generating-2048-RSA-key.rst @@ -0,0 +1,304 @@ +============================ +Generating 2048-bit RSA keys +============================ + +In this section, we describe how to generate 2048-bit RSA keys. + + +Key length of RSA +================= + +In 2005, NIST (National Institute of Standards and Technology, USA) +has issued the first revision of NIST Special Publication 800-57, +"Recommendation for Key Management". + +In 800-57, NIST advises that 1024-bit RSA keys will no longer be +viable after 2010 and advises moving to 2048-bit RSA keys. NIST +advises that 2048-bit keys should be viable until 2030. + +As of 2010, GnuPG's default for generating RSA key is 2048-bit. + +Some people have preference on RSA 4096-bit keys, considering +"longer is better". + +However, "longer is better" is not always true. When it's long, it +requires more computational resource, memory and storage, and it +consumes more power for nomal usages. These days, many people has +enough computational resource, that would be true, but less is better +for power consumption. + +For security, the key length is a single factor. We had and will have +algorithm issues, too. It is true that it's difficult to update +our public keys, but this problem wouldn't be solved by just have +longer keys. + +We deliberately support only RSA 2048-bit keys for Gnuk, considering +device computation power and host software constraints. + +Thus, the key size is 2048-bit in the examples below. + +Generating keys on host PC +========================== + +Here is the example session to generate main key and a subkey for encryption. + +I invoke GnuPG with ``--gen-key`` option. :: + + $ gpg --gen-key + gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + +and GnuPG asks kind of key. Select ``RSA and RSA``. :: + + Please select what kind of key you want: + (1) RSA and RSA (default) + (2) DSA and Elgamal + (3) DSA (sign only) + (4) RSA (sign only) + Your selection? 1 + RSA keys may be between 1024 and 4096 bits long. + +and select 2048-bit (as Gnuk Token only supports this). :: + + What keysize do you want? (2048) + Requested keysize is 2048 bits + +and select expiration of the key. :: + + Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years + Key is valid for? (0) 0 + Key does not expire at all + +Confirm key types, bitsize and expiration. :: + + Is this correct? (y/N) y + +Then enter user ID. :: + + You need a user ID to identify your key; the software constructs the user ID + from the Real Name, Comment and Email Address in this form: + "Heinrich Heine (Der Dichter) " + + Real name: Niibe Yutaka + Email address: gniibe@fsij.org + Comment: + You selected this USER-ID: + "Niibe Yutaka " + + Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o + +and enter passphrase for this **key on host PC**. +Note that this is a passphrase for the key on host PC. +It is different thing to the password of Gnuk Token. + +We enter two same inputs two times +(once for passphrase input, and another for confirmation). :: + + You need a Passphrase to protect your secret key. + + +Then, GnuPG generate keys. It takes some time. :: + + We need to generate a lot of random bytes. It is a good idea to perform + some other action (type on the keyboard, move the mouse, utilize the + disks) during the prime generation; this gives the random number + generator a better chance to gain enough entropy. + ...+++++ + +++++ + We need to generate a lot of random bytes. It is a good idea to perform + some other action (type on the keyboard, move the mouse, utilize the + disks) during the prime generation; this gives the random number + generator a better chance to gain enough entropy. + ..+++++ + + Not enough random bytes available. Please do some other work to give + the OS a chance to collect more entropy! (Need 15 more bytes) + ...+++++ + gpg: key 28C0CD7C marked as ultimately trusted + public and secret key created and signed. + + gpg: checking the trustdb + gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model + pub 2048R/4CA7BABE 2010-10-15 + Key fingerprint = 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE + uid Niibe Yutaka + sub 2048R/084239CF 2010-10-15 + $ + +Done. + +Then, we create authentication subkey. Authentication subkey is not that common, but very useful (for SSH authentication). As it is not that common, we need ``--expert`` option for GnuPG. :: + + $ gpg --expert --edit-key 4CA7BABE + gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + Secret key is available. + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: ultimate validity: ultimate + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + [ultimate] (1). Niibe Yutaka + + gpg> + +Here, it displays that there are main key and a subkey. +It prompts sub-command with ``gpg>`` . + +Here, we enter ``addkey`` sub-command. +Then, we enter the passphrase of **key on host PC**. +It's the one we entered above as . :: + + gpg> addkey + Key is protected. + + You need a passphrase to unlock the secret key for + user: "Niibe Yutaka " + 2048-bit RSA key, ID 4CA7BABE, created 2010-10-15 + + gpg: gpg-agent is not available in this session + +GnuPG asks kind of key. We select ``RSA (set your own capabilities)``. :: + + Please select what kind of key you want: + (3) DSA (sign only) + (4) RSA (sign only) + (5) Elgamal (encrypt only) + (6) RSA (encrypt only) + (7) DSA (set your own capabilities) + (8) RSA (set your own capabilities) + Your selection? 8 + +And select ``Authenticate`` for the capabilities for this key. Initially, it's ``Sign`` and ``Encrypt``. I need to deselect ``Sign`` and ``Encryp``, and select ``Authenticate``. To do that, I enter ``s``, ``e``, and ``a``. :: + + Possible actions for a RSA key: Sign Encrypt Authenticate + Current allowed actions: Sign Encrypt + + (S) Toggle the sign capability + (E) Toggle the encrypt capability + (A) Toggle the authenticate capability + (Q) Finished + + Your selection? s + + Possible actions for a RSA key: Sign Encrypt Authenticate + Current allowed actions: Encrypt + + (S) Toggle the sign capability + (E) Toggle the encrypt capability + (A) Toggle the authenticate capability + (Q) Finished + + Your selection? e + + Possible actions for a RSA key: Sign Encrypt Authenticate + Current allowed actions: + + (S) Toggle the sign capability + (E) Toggle the encrypt capability + (A) Toggle the authenticate capability + (Q) Finished + + Your selection? a + + Possible actions for a RSA key: Sign Encrypt Authenticate + Current allowed actions: Authenticate + + (S) Toggle the sign capability + (E) Toggle the encrypt capability + (A) Toggle the authenticate capability + (Q) Finished + +OK, we set the capability of ``Authenticate``. +We enter ``q`` to finish setting capabilities. :: + + Your selection? q + +GnuPG asks bitsize and expiration, we enter 2048 for bitsize and no expiration. +Then, we confirm that we really create the key. :: + + RSA keys may be between 1024 and 4096 bits long. + What keysize do you want? (2048) + Requested keysize is 2048 bits + Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years + Key is valid for? (0) 0 + Key does not expire at all + Is this correct? (y/N) y + Really create? (y/N) y + +Then, GnuPG generate the key. :: + + We need to generate a lot of random bytes. It is a good idea to perform + some other action (type on the keyboard, move the mouse, utilize the + disks) during the prime generation; this gives the random number + generator a better chance to gain enough entropy. + .......+++++ + +++++ + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: ultimate validity: ultimate + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ultimate] (1). Niibe Yutaka + + gpg> + +We save the key (to the storage of the host PC. :: + + gpg> save + $ + +Now, we have three keys (one primary key for signature and certification, subkey for encryption, and another subkey for authentication). + + +Publishing public key +===================== + +We make a file for the public key by ``--export`` option of GnuPG. :: + + $ gpg --armor --output .asc --export + +We can publish the file by web server. Or we can publish the key +to a keyserver, by invoking GnuPG with ``--send-keys`` option. :: + + $ gpg --keyserver pool.sks-keyservers.net --send-keys + +Here, pool.sks-keyservers.net is a keyserver, which is widely used. + + +Backup the private key +====================== + +There are some ways to back up private key, such that backup .gnupg +directory entirely, use of paperkey. Here we describe backup by ASCII +file. ASCII file is good, because it has less risk on transfer. +Binary file has a risk to be modified on transfer. + +Note that the key on host PC is protected by passphrase (which +is in the example above). Using the key +from the backup needs this passphrase. It is common that +people will forget passphrase for backup. Never forget it. +You have been warned. + +To make ASCII backup for private key, +invokde GnuPG with ``--armor`` option and ``--export-secret-keys`` +specifying the key identifier. :: + + $ gpg --armor --output .asc --export-secret-keys + +From the backup, +we can recover privet key by invoking GnuPG with ``--import`` option. :: + + $ gpg --import .asc diff --git a/doc/gnome3-gpg-settings.rst b/doc/gnome3-gpg-settings.rst new file mode 100644 index 0000000..f6bb312 --- /dev/null +++ b/doc/gnome3-gpg-settings.rst @@ -0,0 +1,30 @@ +========================== +GnuPG settings for GNOME 3 +========================== + +In the article `GnuPG settings`_, I wrote how I disable GNOME-keyrings for SSH. + +It was for GNOME 2. The old days was good, we just disabled GNOME-keyrings interference to SSH and customizing our desktop was easy for GNU and UNIX users. + +.. _GnuPG settings: gpg-settings + + +GNOME keyrings in GNOME 3 +========================= + +It seems that it is more integrated into the desktop. It is difficult to kill it. It would be possible to kill it simply, but then, I can't use, say, wi-fi access (which needs to access "secrets") any more. + +We can't use GNOME configuration tool to disable interference by GNOME keyrings any more. It seems that desktop should not have customization these days. + + +GNOME-SESSION-PROPERTIES +======================== + +After struggling some ours, I figured out it is GNOME-SESSION-PROPERTIES to disable the interference. Invoking:: + + $ gnome-session-properties + +and at the tab of "Startup Programs", I removed radio check buttons for "GPG Password Agent" and "SSH Key Agent". + + +Now, I use gpg-agent for GnuPG Agent and SSH agent with Gnuk Token. diff --git a/doc/gnuk-keytocard-noremoval.rst b/doc/gnuk-keytocard-noremoval.rst new file mode 100644 index 0000000..f350376 --- /dev/null +++ b/doc/gnuk-keytocard-noremoval.rst @@ -0,0 +1,177 @@ +============================================= +Key import from PC to Gnuk Token (no removal) +============================================= + +This document describes how I put my **keys on PC** to the Token without removing keys from PC. + +The difference is just not-to-save changes after key imports. + +.. BREAK + +After personalization, I put my keys into the Token. + +Here is the log. + +I invoke GnuPG with my key (4ca7babe) and with ``--homedir`` option to specify the directory which contains my secret keys. :: + + $ gpg --homedir=/home/gniibe/tmp/gnuk-testing-dir --edit-key 4ca7babe + gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + Secret key is available. + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: ultimate validity: ultimate + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ultimate] (1). NIIBE Yutaka + + +Then, GnuPG enters its own command interaction mode. The prompt is ``gpg>``. +To enable ``keytocard`` command, I type ``toggle`` command. :: + + gpg> toggle + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + ssb 2048R/084239CF created: 2010-10-15 expires: never + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +Firstly, I import my primary key into Gnuk Token. +I type ``keytocard`` command, answer ``y`` to confirm keyimport, +and type ``1`` to say it's signature key. :: + + gpg> keytocard + Really move the primary key? (y/N) y + gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00' + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + + Please select where to store the key: + (1) Signature key + (3) Authentication key + Your selection? 1 + +Then, GnuPG asks two passwords. One is the passphrase of **keys on PC** and another is the password of **Gnuk Token**. Note that the password of the token and the password of the keys on PC are different things, although they can be same. + +I enter these passwords. :: + + You need a passphrase to unlock the secret key for + user: "NIIBE Yutaka " + 2048-bit RSA key, ID 4CA7BABE, created 2010-10-15 + + gpg: writing new key + gpg: 3 Admin PIN attempts remaining before card is permanently locked + + Please enter the Admin PIN + Enter Admin PIN: + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +The primary key is now on the Token and GnuPG says its card-no (F517 00000001) , where F517 is the vendor ID of FSIJ. + +Secondly, I import my subkey of encryption. I select key number '1'. :: + + gpg> key 1 + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/084239CF created: 2010-10-15 expires: never + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +You can see that the subkey is marked by '*'. +I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``2`` as it's encryption key. :: + + gpg> keytocard + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + + Please select where to store the key: + (2) Encryption key + Your selection? 2 + +Then, GnuPG asks the passphrase of **keys on PC** again. I enter. :: + + You need a passphrase to unlock the secret key for + user: "NIIBE Yutaka " + 2048-bit RSA key, ID 084239CF, created 2010-10-15 + + gpg: writing new key + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +The sub key is now on the Token and GnuPG says its card-no for it. + +I type ``key 1`` to deselect key number '1'. :: + + gpg> key 1 + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +Thirdly, I select sub key of authentication which has key number '2'. :: + + gpg> key 2 + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +You can see that the subkey number '2' is marked by '*'. +I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``3`` as it's authentication key. :: + + gpg> keytocard + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + + Please select where to store the key: + (3) Authentication key + Your selection? 3 + +Then, GnuPG asks the passphrase of **keys on PC** again. I enter. :: + + You need a passphrase to unlock the secret key for + user: "NIIBE Yutaka " + 2048-bit RSA key, ID 5BB065DC, created 2010-10-22 + + gpg: writing new key + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/5BB065DC created: 2010-10-22 expires: never + card-no: F517 00000001 + (1) NIIBE Yutaka + +The sub key is now on the Token and GnuPG says its card-no for it. + +Lastly, I quit GnuPG. Note that I **don't** save changes. :: + + gpg> quit + Save changes? (y/N) n + Quit without saving? (y/N) y + $ + +All keys are imported to Gnuk Token now. diff --git a/doc/gnuk-keytocard.rst b/doc/gnuk-keytocard.rst new file mode 100644 index 0000000..2c49292 --- /dev/null +++ b/doc/gnuk-keytocard.rst @@ -0,0 +1,183 @@ +================================ +Key import from PC to Gnuk Token +================================ + +This document describes how I put my **keys on PC** to the Token, and remove keys from PC. + +Note that there is **no ways** to export keys from the Token, so please be careful. + +.. BREAK + +If you want to import same keys to multiple Tokens, please copy ``.gnupg`` directory before. In my case, I do something like following: :: + + $ cp -a .gnupg tmp/gnuk-testing-dir + +See `another document`_ to import keys to the Token from copied directory. + +.. _another document: gnuk-keytocard-noremoval + +After personalization, I put my keys into the Token. + +Here is the log. + +I invoke GnuPG with my key (4ca7babe). :: + + $ gpg --edit-key 4ca7babe + gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + Secret key is available. + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: ultimate validity: ultimate + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ultimate] (1). NIIBE Yutaka + + +Then, GnuPG enters its own command interaction mode. The prompt is ``gpg>``. +To enable ``keytocard`` command, I type ``toggle`` command. :: + + gpg> toggle + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + ssb 2048R/084239CF created: 2010-10-15 expires: never + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +Firstly, I import my primary key into Gnuk Token. +I type ``keytocard`` command, answer ``y`` to confirm keyimport, +and type ``1`` to say it's signature key. :: + + gpg> keytocard + Really move the primary key? (y/N) y + gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00' + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + + Please select where to store the key: + (1) Signature key + (3) Authentication key + Your selection? 1 + +Then, GnuPG asks two passwords. One is the passphrase of **keys on PC** and another is the password of **Gnuk Token**. Note that the password of the token and the password of the keys on PC are different things, although they can be same. + +I enter these passwords. :: + + You need a passphrase to unlock the secret key for + user: "NIIBE Yutaka " + 2048-bit RSA key, ID 4CA7BABE, created 2010-10-15 + + gpg: writing new key + gpg: 3 Admin PIN attempts remaining before card is permanently locked + + Please enter the Admin PIN + Enter Admin PIN: + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +The primary key is now on the Token and GnuPG says its card-no (F517 00000001) , where F517 is the vendor ID of FSIJ. + +Secondly, I import my subkey of encryption. I select key number '1'. :: + + gpg> key 1 + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/084239CF created: 2010-10-15 expires: never + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +You can see that the subkey is marked by '*'. +I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``2`` as it's encryption key. :: + + gpg> keytocard + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + + Please select where to store the key: + (2) Encryption key + Your selection? 2 + +Then, GnuPG asks the passphrase of **keys on PC** again. I enter. :: + + You need a passphrase to unlock the secret key for + user: "NIIBE Yutaka " + 2048-bit RSA key, ID 084239CF, created 2010-10-15 + + gpg: writing new key + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +The sub key is now on the Token and GnuPG says its card-no for it. + +I type ``key 1`` to deselect key number '1'. :: + + gpg> key 1 + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +Thirdly, I select sub key of authentication which has key number '2'. :: + + gpg> key 2 + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/5BB065DC created: 2010-10-22 expires: never + (1) NIIBE Yutaka + +You can see that the subkey number '2' is marked by '*'. +I type ``keytocard`` command to import this subkey to Gnuk Token. I select ``3`` as it's authentication key. :: + + gpg> keytocard + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + + Please select where to store the key: + (3) Authentication key + Your selection? 3 + +Then, GnuPG asks the passphrase of **keys on PC** again. I enter. :: + + You need a passphrase to unlock the secret key for + user: "NIIBE Yutaka " + 2048-bit RSA key, ID 5BB065DC, created 2010-10-22 + + gpg: writing new key + + sec 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb* 2048R/5BB065DC created: 2010-10-22 expires: never + card-no: F517 00000001 + (1) NIIBE Yutaka + +The sub key is now on the Token and GnuPG says its card-no for it. + +Lastly, I save changes of **keys on PC** and quit GnuPG. :: + + gpg> save + $ + +All secret keys are imported to Gnuk Token now. On PC, only references (card-no) to the Token remain. diff --git a/doc/gnuk-personalization.rst b/doc/gnuk-personalization.rst new file mode 100644 index 0000000..51d737c --- /dev/null +++ b/doc/gnuk-personalization.rst @@ -0,0 +1,140 @@ +============================= +Personalization of Gnuk Token +============================= + + +Personalize your Gnuk Token +=========================== + +Invoke GnuPG with the option ``--card-edit``. :: + + $ gpg --card-edit + gpg: detected reader `FSIJ Gnuk (0.12-34006E06) 00 00' + Application ID ...: D276000124010200F517000000010000 + Version ..........: 2.0 + Manufacturer .....: FSIJ + Serial number ....: 00000001 + Name of cardholder: [not set] + Language prefs ...: [not set] + Sex ..............: unspecified + URL of public key : [not set] + Login data .......: [not set] + Signature PIN ....: forced + Key attributes ...: 2048R 2048R 2048R + Max. PIN lengths .: 127 127 127 + PIN retry counter : 3 3 3 + Signature counter : 0 + Signature key ....: [none] + Encryption key....: [none] + Authentication key: [none] + General key info..: [none] + +It shows the status of the card (as same as the output of ``gpg --card-status``). It shows token's name and its USB serial string (0.12-34006E06) from PC/SC-lite. + +Then, GnuPG enters its own command interaction mode. The prompt is ``gpg/card>``. + +In the OpenPGPcard specification, there are two passwords: one is +user-password and another is admin-password. In the specification, +user-password is refered as PW1, and admin-password is refered as PW3. + +Note that people sometimes use different words than "password" to +refer same thing, in GnuPG and its applications. For example, the +output explained above includes the word "PIN" (Personal +Identification Number), and the helper program for input is named +"pinentry". Note that it is OK (and recommended) to include +characters other than digits for the case of OpenPGPcard. + +Besides, some people sometimes prefer the word "passphrase" to +"password", as it can encourage to have longer string, but it means +same thing and it just refer user-password or admin-password. + +Firstly, I change PIN of card user from factory setting (of "123456"). Note that, by only changing user's PIN, it enables "admin less mode" of Gnuk. "Admin less mode" means that admin password will become same one of user's. That is, PW1 = PW3. Note that *the length of PIN should be more than (or equals to) 8* for "admin less mode". :: + + gpg/card> passwd + gpg: OpenPGP card no. D276000124010200F517000000010000 detected + + Please enter the PIN + Enter PIN: 123456 + + New PIN + Enter New PIN: + + New PIN + Repeat this PIN: + PIN changed. + +The "admin less mode" is Gnuk only feature, not defined in the +OpenPGPcard specification. By using "admin less mode", it will be +only a sigle password for user to memorize, and it will be easier if a token +is used by an individual. + +(If you want normal way ("admin full mode" in Gnuk's term), that is, user-password *and* admin-password independently, please change admin-password at first. Then, the token works as same as OpenPGPcard specification with regards to PW1 and PW3.) + +Secondly, enabling admin command, I put name of mine. Note that I input user's PIN (which I set above) here, because it is "admin less mode". :: + + gpg/card> admin + Admin commands are allowed + + gpg/card> name + Cardholder's surname: Niibe + Cardholder's given name: Yutaka + gpg: 3 Admin PIN attempts remaining before card is permanently locked + + Please enter the Admin PIN + Enter Admin PIN: + +Thirdly, I put some other informations, such as language, sex, login, and URL. URL specifies the place where I put my public keys. :: + + gpg/card> lang + Language preferences: ja + + gpg/card> sex + Sex ((M)ale, (F)emale or space): m + + gpg/card> url + URL to retrieve public key: http://www.gniibe.org/gniibe.asc + + gpg/card> login + Login data (account name): gniibe + +Since I don't force PIN input everytime, toggle it to non-force-pin-for-signature. :: + + gpg/card> forcesig + +Lastly, I setup reset code. This is optional. :: + + gpg/card> passwd + gpg: OpenPGP card no. D276000124010200F517000000010000 detected + + 1 - change PIN + 2 - unblock PIN + 3 - change Admin PIN + 4 - set the Reset Code + Q - quit + + Your selection? 4 + gpg: 3 Admin PIN attempts remaining before card is permanently locked + + Please enter the Admin PIN + Enter Admin PIN: + + New Reset Code + Enter New PIN: + + New Reset Code + Repeat this PIN: + Reset Code set. + + 1 - change PIN + 2 - unblock PIN + 3 - change Admin PIN + 4 - set the Reset Code + Q - quit + + Your selection? q + +Then, I quit. :: + + gpg/card> quit + +That's all. diff --git a/doc/gnuk-token-initial-configuration.rst b/doc/gnuk-token-initial-configuration.rst new file mode 100644 index 0000000..d2a5c9a --- /dev/null +++ b/doc/gnuk-token-initial-configuration.rst @@ -0,0 +1,34 @@ +=================================== +Initial Configuration of Gnuk Token +=================================== + +Conditions +========== + +I assume you are using GNU/Linux. + + +Preparation +=========== + +We need to kill ``scdaemon`` before configuring Gnuk Token. :: + + $ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye + + +Serial Number (optional) +======================== + +In the file ``GNUK_SERIAL_NUMBER``, each line has email and 6-byte serial number. + +The tool ``../tool/gnuk_put_binary.py`` examines environment variable of ``EMAIL``, and writes serial number to Gnuk Token. :: + + $ ../tool/gnuk_put_binary.py -s ../GNUK_SERIAL_NUMBER + Writing serial number + Token: FSIJ Gnuk (0.12-38FF6A06) 00 00 + ATR: 3B DA 11 FF 81 B1 FE 55 1F 03 00 31 84 73 80 01 40 00 90 00 24 + + +The tool ``../tool/gnuk_put_binary.py`` is for PC/SC Lite. Use +``../tool/gnuk_put_binary_libusb.py`` instead, if you don't use +PC/SC Lite but use libusb directly. diff --git a/doc/gpg-settings.rst b/doc/gpg-settings.rst new file mode 100644 index 0000000..d573995 --- /dev/null +++ b/doc/gpg-settings.rst @@ -0,0 +1,41 @@ +.. -*- coding: utf-8 -*- + +============== +GnuPG settings +============== + +Here is my GnuPG settings. + +.gnupg/gpg.conf +=============== + +I create ``.gnupg/gpg.conf`` file with the following content. :: + + use-agent + personal-digest-preferences SHA256 + cert-digest-algo SHA256 + default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed + + default-key 0x4ca7babe + + +Let gpg-agent manage SSH key +============================ + +I deactivate seahose-agent. Also, I deactivate gnome-keyring managing SSH key. :: + + $ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false + +Then, I create ``.gnupg/gpg-agent.conf`` file with the following content. :: + + enable-ssh-support + + +References +========== + +* `Creating a new GPG key`_ +* `Use OpenPGP Keys for OpenSSH, how to use gpg with ssh`_ + +.. _Creating a new GPG key: http://keyring.debian.org/creating-key.html +.. _Use OpenPGP Keys for OpenSSH, how to use gpg with ssh: http://www.programmierecke.net/howto/gpg-ssh.html diff --git a/doc/images/gnuk-sticker.png b/doc/images/gnuk-sticker.png new file mode 100644 index 0000000..511c783 Binary files /dev/null and b/doc/images/gnuk-sticker.png differ diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..cbf8207 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,37 @@ +.. Gnuk Documentation documentation master file, created by + sphinx-quickstart on Wed Jul 4 15:29:05 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + Copyright (C) 2012 NIIBE Yutaka + Copyright (C) 2012 Free Software Initiative of Japan + This document is licensed under a CC-BY-SA 3.0 Unported License + +Gnuk Documentation +================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + intro.rst + development.rst + stop-scdaemon.rst + udev-rules.rst + gnuk-token-initial-configuration.rst + gnuk-personalization.rst + generating-2048-RSA-key.rst + gnuk-keytocard.rst + gnuk-keytocard-noremoval.rst + using-gnuk-token-with-another-computer.rst + gpg-settings.rst + gnome3-gpg-settings.rst + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/intro.rst b/doc/intro.rst new file mode 100644 index 0000000..792018b --- /dev/null +++ b/doc/intro.rst @@ -0,0 +1,69 @@ +Introduction +============ + + +What's Gnuk? +------------ + +Gnuk is an implementation of USB cryptographic token for GNU Privacy +Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on +STM32F103 processor. + + +Cryptographic token and feature of Gnuk +--------------------------------------- + +Cryptographic token is a store of private keys and it computes cryptographic +functions on the device. + +The idea is to separate important secrets to independent device, +from where nobody can extract them. + + +Development Environment +----------------------- + +See :doc:`development` for development environment for Gnuk. +Gnuk is developed on the environment where there are only Free Software. + + +Target boards for running Gnuk +------------------------------ + +Hardware requirement for Gnuk is the micro controller STM32F103. +In version 1.0, Gnuk supports following boards. + +* FST-01 (Flying Stone Tiny ZERO-ONE) + +* Olimex STM32-H103 + +* CQ STARM + +* STBee + +* STBee Mini + +* STM32 part of STM8S Discovery Kit + + +Host prerequisites for using Gnuk Token +--------------------------------------- + +* GNU Privacy Guard (GnuPG) + +* libusb + +* [Optional] PC/SC lite (pcscd, libccid) + +* SSH: openssh + +* Web: scute, firefox + + +Usages +------ + +* Sign with GnuPG +* Decrypt with GnuPG +* Use with OpenSSH +* Use with Firefox for X.509 client certificate authentication diff --git a/doc/DEMO b/doc/note/DEMO similarity index 100% rename from doc/DEMO rename to doc/note/DEMO diff --git a/doc/DEMO-2 b/doc/note/DEMO-2 similarity index 100% rename from doc/DEMO-2 rename to doc/note/DEMO-2 diff --git a/doc/HACKING b/doc/note/HACKING similarity index 97% rename from doc/HACKING rename to doc/note/HACKING index 5087246..fc5be9a 100644 --- a/doc/HACKING +++ b/doc/note/HACKING @@ -1,4 +1,4 @@ -* Random Number Generator +* [DONE] Random Number Generator RNG is needed for Data Encryption Key to encrypt private key (P and Q). It is important to collect enough entropy. Perhaps, it would diff --git a/doc/note/NOTES b/doc/note/NOTES new file mode 100644 index 0000000..7b4a052 --- /dev/null +++ b/doc/note/NOTES @@ -0,0 +1,89 @@ +USB communication (current) +=========================== + +* Get response, command chaining, short APDU only. + + +If it were only for token and no smartcard: + +* Get response, command chaining and short APDU would be considered + useless. + +* It would be wise to use extended APDU and CCID/ICCD block chaining. + +The question would be: When lower layer (CCID/ICCD layer) support +enough mechanism of block assembly, why not use one in the application +layer (ISO 7816)? + +For token implementation, CCID/ICCD would be lower layer and ISO 7816 +would be higher layer, but it's different in fact. The figure of +communication is like:: + + host <-----------> reader <---------> smartcard + CCID/ICCD ISO 7816 + + host <--> token + +Given the situation host side (GnuPG) already has the features of +handling get response, command chaining, and short APDU only, it is +rather better to do that on token side too. + +Besides, supporting extended APDU on host side, it would be needed to +prepare 64KB buffer (that's the maximum size), as there is no explicit +limitation for buffer size. 64KB would be large, and this could be +avoided when we use short APDU only. + + +USB communication (second attempt) +================================== + +* No get response, no command chaining, but extended APDU and extended + Lc and Le. I think that this keep the code simple. + +* The value of dwMaxCCIDMessageLength is 320, that's the size + of header of ICC block plus size of maximum APDU (by 64 + granularity). Still, some ccid implementation (ccid 1.3.11, for + example) sends ICC block using chaining unfortunately, so we keep + the code of ICC block chaining. + + +USB communication (initial attempt) +=================================== + +* Once in the past (version <= 0.4), the value of + dwMaxCCIDMessageLength was 64 and we supported CCID/ICCD block chaining, + so that we could not handle multple Bulk transactions. + + +OpenPGP card protocol implementation +==================================== + +I try to follow "no clear password(s)" policy, even if it is on +protected flash memory. Further, keystrings for user and reset code +are removed after key imports. Because of this, replacing keys are +not possible without password information. (Thus, replacing existing +keys are not supported.) + +Therefore, there is "no clear password" and "no keystrings" on flash +ROM when Gnuk is used by admin-less mode. When it is used with admin, +the keystring of admin is on flash ROM. + + +How a private key is stored +=========================== + +KEYPTR + ----> [ P ][ Q ][ N ] + <---encrypted----><--- plain ----> + +key_addr 4-byte +initial_vector (random) 16-byte +checksum_encrypted 16-byte +dek_encrypted_by_keystring_pw1 16-byte +dek_encrypted_by_keystring_rc 16-byte +dek_encrypted_by_keystring_pw3 16-byte + +... decrypted to + +[ P ][ Q ] +checksum 16-byte diff --git a/doc/note/firmware-update b/doc/note/firmware-update new file mode 100644 index 0000000..686bae7 --- /dev/null +++ b/doc/note/firmware-update @@ -0,0 +1,130 @@ +Firmware update feature +======================= + +The firmware update feature of Gnuk is experimental. Please be +careful using that. + +Note that updating firmware, all data objects and keys will be +removed. There is _no way_ to preserve those data. + + +Preparation +=========== + +In addition to settings of Gnuk, I create a file +/etc/udev/rules.d/92-gnuk.rules:: + + # For updating firmware, permission settings are needed. + + SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ + ENV{ID_USB_INTERFACES}=="*:ff0000:*", GROUP="pcscd" + + +While I am a member of group "pcscd" in /etc/group. + +This is needed for reGNUal, the firmware update program. + + +Registering a public key for firmware update +============================================ + +You need to register a public key to update the firmware. It should +be RSA 2048-bit. + +One way to extract public key data is by using "gpg-connect-agent" +command connecting gpg-agent. + +We can examine key information of gpg-agent by "KEYINFO" command. +Here is my example:: + + $ gpg-connect-agent "KEYINFO --list" /bye + S KEYINFO 65F67E742101C7FE6D5B33FCEFCF4F65EAF0688C T D276000124010200F517000000010000 OPENPGP.2 - - - + S KEYINFO 101DE7B639FE29F4636BDEECF442A9273AFA6565 T D276000124010200F517000000010000 OPENPGP.1 - - - + S KEYINFO 5D6C89682D07CCFC034AF508420BF2276D8018ED T D276000124010200F517000000010000 OPENPGP.3 - - - + OK + +I have three keys in my token. + +With the script below, I extract public key of the keygrip +5D6C89682D07CCFC034AF508420BF2276D8018ED into the file: 5D6C8968.bin:: + + $ ./get_public_key.py 5D6C89682D07CCFC034AF508420BF2276D8018ED + +Here is the script, get_public_key.py:: + + #! /usr/bin/python + + import sys, binascii + from subprocess import check_output + + def get_gpg_public_key(keygrip): + result = check_output(["gpg-connect-agent", "READKEY %s" % keygrip, "/bye"]) + key = "" + while True: + i = result.find('%') + if i < 0: + key += result + break + hex_str = result[i+1:i+3] + key += result[0:i] + key += chr(int(hex_str,16)) + result = result[i+3:] + + pos = key.index("D (10:public-key(3:rsa(1:n257:") + 31 # skip NUL too + key = key[pos:-17] # )(1:e3:XYZ)))\nOK\n + if len(key) != 256: + raise ValueError, binascii.hexlify(key) + return key + + if __name__ == '__main__': + keygrip = sys.argv[1] + k = get_gpg_public_key(keygrip) + shorthand = keygrip[0:8] + ".bin" + f = open(shorthand,"w") + f.write(k) + f.close() + + +Then, we can put the data of public key into token by:: + + $ tool/gnuk_put_binary_libusb.py -k 0 5D6C8968.bin + + +Invoking firmware update +======================== + +We specify reGNUal binary and Gnuk binary. + + $ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin + + +Two or more tokens +================== + +Currently, GnuPG doesn't support multiple devices connected to the +host. + +In order to update the firmware of a TARGET token, we use GnuPG to +authenticate with public key. It is assumed that you have another +AUTH token for this. This situation is somewhat complicated. + +What I do is: +(1) Don't run PC/SC daemon:: + + # /etc/init.d/pcscd stop + +(2) To make sure, kill scdaemon:: + + $ killall -9 scdaemon + +(3) Insert the AUTH token to USB, and use it:: + + $ gpg --card-status + +(4) Insert the TARGET token to USB (after scdaemon communicates AUTH + token), and invoke gnuk_upgrade.py. + In this situation, gnuk_upgrade.py tries to connect one of tokens, + but a connection to the AUTH token will fail because scdaemon is + connecting to that device, and will be expected to connect to the + TARGET token succesufully, instead. +-- diff --git a/doc/note/settings-for-DnDpinentry b/doc/note/settings-for-DnDpinentry new file mode 100644 index 0000000..c0c52ad --- /dev/null +++ b/doc/note/settings-for-DnDpinentry @@ -0,0 +1,34 @@ +On GNU/Linux Desktop, I use udisks-glue so that DnDpinentry folder can +be mounted with sync and noatime options. + +After installing udisks-glue, I invoke gnome-session-properties to +add udisks-glue to "Startup Program". + +Then, I have two files to configure udisks (disable udisks for +DnDpinentry) and udisks-glue (enable and specify options for DnDpinentry). + +/etc/udev/rules.d/88-udisks.rules +--------------- +ENV{ID_VENDOR}=="FSIJ", ENV{DEVTYPE}=="disk", ENV{ID_FS_LABEL}=="DnDpinentry", ENV{UDISKS_PRESENTATION_NOPOLICY}="1" +--------------- + +~/.udisks-glue.conf +--------------- +filter gone { + label = "DnDpinentry" + optical = false +} + +match gone { + automount = true + automount_options = { sync, noatime } +} +--------------- + +We need following setting for pinentry. Or else, you can't do +anything when pinentry grabs mouse focus. + +~/.gnupg/gpg-agent.conf +--------------- +no-grab +--------------- diff --git a/doc/stop-scdaemon.rst b/doc/stop-scdaemon.rst new file mode 100644 index 0000000..7a4dbbd --- /dev/null +++ b/doc/stop-scdaemon.rst @@ -0,0 +1,37 @@ +=========================== +Stopping/Resetting SCDAEMON +=========================== + +There is a daemon named ``scdaemon`` behind gpg-agent, which handles +communication to smartcard/token. + +Ideally, we don't need to care about ``scdaemon``, and it should +handle everything automatically. But, there are some cases (because +of bugs), where we need to talk to the daemon directly, in practice. + + +How to communicate SCDAEMON +=========================== + +We have a utility to communicate with a running gpg-agent, that's +gpg-connect-agent. We can use it to communicate with scdaemon, +as it supports sub-command "SCD", exactly for this purpose. + + +Stopping SCDAEMON +================= + +To stop SCDAEMON and let it exit, type:: + + $ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye + +Then, you can confirm that there is no SCDAEMON any more by ``ps`` +command. + + +Let GPG-AGENT/SCDAEMON learn +============================ + +To let gpg-agent/scdaemon learn, type:: + + $ gpg-connect-agent learn /bye diff --git a/doc/udev-rules.rst b/doc/udev-rules.rst new file mode 100644 index 0000000..7f8ad26 --- /dev/null +++ b/doc/udev-rules.rst @@ -0,0 +1,51 @@ +=============================================== +Device Configuration for Gnuk Token with libusb +=============================================== + +In order to use Gnuk Token with libusb, configuration of device is +needed for permissions. Note that this is not needed for the case of +PC/SC Lite, as it has its own device configuration. + + +udev rules for Gnuk Token +========================= + +In case of Debian, there is a file /lib/udev/rules.d/60-gnupg.rules, +when you install "gnupg" package. This is the place we need to change. +We add lines for Gnuk Token to give a desktop user the permission to +use the device. We specify USB ID of Gnuk Token (by FSIJ):: + + --- /lib/udev/rules.d/60-gnupg.rules.orig 2012-06-24 21:51:26.000000000 +0900 + +++ /lib/udev/rules.d/60-gnupg.rules 2012-07-13 17:18:55.149587687 +0900 + @@ -10,4 +10,7 @@ + ATTR{idVendor}=="04e6", ATTR{idProduct}=="5115", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" + ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" + + +# Gnuk + +ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" + + + LABEL="gnupg_rules_end" + +When we install "gnupg2" package only (with no "gnupg" package), +there will be no udev rules (there is a bug report #543217 for this issue). +In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules:: + + SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \ + ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg" + +Usually, udev daemon automatically handles for the changes of configuration +files. If not, please let the daemon reload rules:: + + # udevadm control --reload-rules + + + + +udev rules for ST-Link/V2 +========================= + +We need to have a udev rule for ST-Link/V2. It's like:: + + ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", GROUP="tape", MODE="664", SYMLINK+="stlink" + +I have this in the file /etc/udev/rules.d/10-stlink.rules. diff --git a/doc/using-gnuk-token-with-another-computer.rst b/doc/using-gnuk-token-with-another-computer.rst new file mode 100644 index 0000000..200fe77 --- /dev/null +++ b/doc/using-gnuk-token-with-another-computer.rst @@ -0,0 +1,173 @@ +====================================== +Using Gnuk Token with another computer +====================================== + +This document describes how you can use Gnuk Token on another PC (which is not the one you generate your keys). + +Note that the Token only brings your secret keys, while ``.gnupg`` directory contains keyrings and trustdb, too. + +.. BREAK + +Fetch the public key and connect it to the Token +================================================ + +Using the Token, we need to put the public key and the secret key reference (to the token) in ``.gnupg``. + +To do that, invoke GnuPG with ``--card-edit`` option. :: + + $ gpg --card-edit + gpg: detected reader `FSIJ Gnuk (0.12-37006A06) 00 00' + Application ID ...: D276000124010200F517000000010000 + Version ..........: 2.0 + Manufacturer .....: FSIJ + Serial number ....: 00000001 + Name of cardholder: Yutaka Niibe + Language prefs ...: ja + Sex ..............: male + URL of public key : http://www.gniibe.org/gniibe.asc + Login data .......: gniibe + Signature PIN ....: not forced + Key attributes ...: 2048R 2048R 2048R + Max. PIN lengths .: 127 127 127 + PIN retry counter : 3 3 3 + Signature counter : 6 + Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE + created ....: 2010-10-15 06:46:33 + Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF + created ....: 2010-10-15 06:46:33 + Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC + created ....: 2010-10-22 06:06:36 + General key info..: [none] + + gpg/card> + +It says, there is no key info related to this token on your PC (``[none]``). + +Fetch the public key from URL specified in the Token. :: + + gpg/card> fetch + gpg: requesting key 4CA7BABE from http server www.gniibe.org + gpg: key 4CA7BABE: public key "NIIBE Yutaka " imported + gpg: no ultimately trusted keys found + gpg: Total number processed: 1 + gpg: imported: 1 (RSA: 1) + + gpg/card> + +Good. The public key is now in ``.gnupg``. We can examine by ``gpg --list-keys``. + +However, the secret key reference (to the token) is not in ``.gnupg`` yet. + +It will be generated when I do ``--card-status`` by GnuPG with correspoinding public key in ``.gnupg``, or just type return at the ``gpg/card>`` prompt. :: + + gpg/card> + + Application ID ...: D276000124010200F517000000010000 + Version ..........: 2.0 + Manufacturer .....: FSIJ + Serial number ....: 00000001 + Name of cardholder: Yutaka Niibe + Language prefs ...: ja + Sex ..............: male + URL of public key : http://www.gniibe.org/gniibe.asc + Login data .......: gniibe + Signature PIN ....: not forced + Key attributes ...: 2048R 2048R 2048R + Max. PIN lengths .: 127 127 127 + PIN retry counter : 3 3 3 + Signature counter : 6 + Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE + created ....: 2010-10-15 06:46:33 + Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF + created ....: 2010-10-15 06:46:33 + Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC + created ....: 2010-10-22 06:06:36 + General key info..: + pub 2048R/4CA7BABE 2010-10-15 NIIBE Yutaka + sec> 2048R/4CA7BABE created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb> 2048R/084239CF created: 2010-10-15 expires: never + card-no: F517 00000001 + ssb> 2048R/5BB065DC created: 2010-10-22 expires: never + card-no: F517 00000001 + + gpg/card> + +OK, now I can use the Token on this computer. + + +Update trustdb for the key on Gnuk Token +======================================== + +Yes, I can use the Token by the public key and the secret key reference to the card. More, I need to update the trustdb. + +To do that I do: :: + + $ gpg --edit-key 4ca7babe + gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + Secret key is available. + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: unknown validity: unknown + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ unknown] (1). NIIBE Yutaka + [ unknown] (2) NIIBE Yutaka + + gpg> + +See, the key is ``unknown`` state. Add trust for that. :: + + gpg> trust + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: unknown validity: unknown + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ unknown] (1). NIIBE Yutaka + [ unknown] (2) NIIBE Yutaka + + Please decide how far you trust this user to correctly verify other users' keys + (by looking at passports, checking fingerprints from different sources, etc.) + + 1 = I don't know or won't say + 2 = I do NOT trust + 3 = I trust marginally + 4 = I trust fully + 5 = I trust ultimately + m = back to the main menu + + Your decision? 5 + Do you really want to set this key to ultimate trust? (y/N) y + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: ultimate validity: unknown + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ unknown] (1). NIIBE Yutaka + [ unknown] (2) NIIBE Yutaka + Please note that the shown key validity is not necessarily correct + unless you restart the program. + + $ + +Next time I invoke GnuPG, it will be ``ultimate`` key. Let's see: :: + + $ gpg --edit-key 4ca7babe + gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + Secret key is available. + + pub 2048R/4CA7BABE created: 2010-10-15 expires: never usage: SC + trust: ultimate validity: ultimate + sub 2048R/084239CF created: 2010-10-15 expires: never usage: E + sub 2048R/5BB065DC created: 2010-10-22 expires: never usage: A + [ultimate] (1). NIIBE Yutaka + [ultimate] (2) NIIBE Yutaka + + gpg> quit + $ diff --git a/polarssl-0.14.0/include/polarssl/aes.h b/polarssl-0.14.0/include/polarssl/aes.h index 5576680..04d47ab 100644 --- a/polarssl-0.14.0/include/polarssl/aes.h +++ b/polarssl-0.14.0/include/polarssl/aes.h @@ -83,6 +83,7 @@ int aes_crypt_ecb( aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); +#if 0 /** * \brief AES-CBC buffer encryption/decryption * Length should be a multiple of the block @@ -103,6 +104,7 @@ int aes_crypt_cbc( aes_context *ctx, unsigned char iv[16], const unsigned char *input, unsigned char *output ); +#endif /** * \brief AES-CFB128 buffer encryption/decryption. diff --git a/polarssl-0.14.0/include/polarssl/bignum.h b/polarssl-0.14.0/include/polarssl/bignum.h index 80399a2..6070332 100644 --- a/polarssl-0.14.0/include/polarssl/bignum.h +++ b/polarssl-0.14.0/include/polarssl/bignum.h @@ -501,7 +501,7 @@ int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); * 1 if memory allocation failed, * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime */ -int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ); +int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng ); /** * \brief Prime number generation @@ -517,7 +517,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ); * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 */ int mpi_gen_prime( mpi *X, int nbits, int dh_flag, - int (*f_rng)(void *), void *p_rng ); + unsigned char (*f_rng)(void *), void *p_rng ); /** * \brief Checkup routine diff --git a/polarssl-0.14.0/include/polarssl/config.h b/polarssl-0.14.0/include/polarssl/config.h index 6c9b61b..880054b 100644 --- a/polarssl-0.14.0/include/polarssl/config.h +++ b/polarssl-0.14.0/include/polarssl/config.h @@ -86,10 +86,12 @@ */ #define POLARSSL_VERSION_C +#ifdef KEYGEN_SUPPORT /* * Enable the prime-number generation code. */ #define POLARSSL_GENPRIME +#endif /* * Uncomment this macro to store the AES tables in ROM. diff --git a/polarssl-0.14.0/include/polarssl/rsa.h b/polarssl-0.14.0/include/polarssl/rsa.h index 5fae794..c0569b4 100644 --- a/polarssl-0.14.0/include/polarssl/rsa.h +++ b/polarssl-0.14.0/include/polarssl/rsa.h @@ -183,7 +183,7 @@ void rsa_init( rsa_context *ctx, * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code */ int rsa_gen_key( rsa_context *ctx, - int (*f_rng)(void *), + unsigned char (*f_rng)(void *), void *p_rng, int nbits, int exponent ); @@ -258,7 +258,7 @@ int rsa_private( rsa_context *ctx, * of ctx->N (eg. 128 bytes if RSA-1024 is used). */ int rsa_pkcs1_encrypt( rsa_context *ctx, - int (*f_rng)(void *), + unsigned char (*f_rng)(void *), void *p_rng, int mode, int ilen, const unsigned char *input, @@ -330,7 +330,7 @@ int rsa_pkcs1_verify( rsa_context *ctx, int hash_id, int hashlen, const unsigned char *hash, - unsigned char *sig ); + const unsigned char *sig ); /** * \brief Free the components of an RSA key diff --git a/polarssl-0.14.0/library/aes.c b/polarssl-0.14.0/library/aes.c index 45f74a6..58c1fb1 100644 --- a/polarssl-0.14.0/library/aes.c +++ b/polarssl-0.14.0/library/aes.c @@ -172,15 +172,15 @@ static const unsigned char FSb[256] = V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) #define V(a,b,c,d) 0x##a##b##c##d -static const unsigned long FT0[256] = { FT }; +static const unsigned long FT0[256] __attribute__((section(".sys.0"))) = { FT }; #undef V #define V(a,b,c,d) 0x##b##c##d##a -static const unsigned long FT1[256] = { FT }; +static const unsigned long FT1[256] __attribute__((section(".sys.1"))) = { FT }; #undef V #define V(a,b,c,d) 0x##c##d##a##b -static const unsigned long FT2[256] = { FT }; +static const unsigned long FT2[256] __attribute__((section(".sys.2"))) = { FT }; #undef V #define V(a,b,c,d) 0x##d##a##b##c @@ -753,6 +753,7 @@ int aes_crypt_ecb( aes_context *ctx, return( 0 ); } +#if 0 /* * AES-CBC buffer encryption/decryption */ @@ -816,6 +817,7 @@ int aes_crypt_cbc( aes_context *ctx, return( 0 ); } +#endif /* * AES-CFB128 buffer encryption/decryption diff --git a/polarssl-0.14.0/library/bignum.c b/polarssl-0.14.0/library/bignum.c index cb1b7eb..dbe85d8 100644 --- a/polarssl-0.14.0/library/bignum.c +++ b/polarssl-0.14.0/library/bignum.c @@ -225,6 +225,7 @@ int mpi_size( const mpi *X ) return( ( mpi_msb( X ) + 7 ) >> 3 ); } +#if 0 /* * Convert an ASCII character to digit value */ @@ -310,7 +311,6 @@ cleanup: return( ret ); } -#if 0 /* * Helper to write the digits high-order first */ @@ -649,7 +649,7 @@ int mpi_cmp_mpi( const mpi *X, const mpi *Y ) return( 0 ); if( i > j ) return( X->s ); - if( j > i ) return( -X->s ); + if( j > i ) return( -Y->s ); if( X->s > 0 && Y->s < 0 ) return( 1 ); if( Y->s > 0 && X->s < 0 ) return( -1 ); @@ -1570,8 +1570,6 @@ cleanup: return( ret ); } -#if defined(POLARSSL_GENPRIME) - /* * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) */ @@ -1665,6 +1663,8 @@ cleanup: return( ret ); } +#if defined(POLARSSL_GENPRIME) + static const int small_prime[] = { 3, 5, 7, 11, 13, 17, 19, 23, @@ -1693,7 +1693,7 @@ static const int small_prime[] = /* * Miller-Rabin primality test (HAC 4.24) */ -int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ) +int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng ) { int ret, i, j, n, s, xs; mpi W, R, T, A, RR; @@ -1755,7 +1755,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ) p = (unsigned char *) A.p; for( j = 0; j < A.n * ciL; j++ ) - *p++ = (unsigned char) f_rng( p_rng ); + *p++ = f_rng( p_rng ); j = mpi_msb( &A ) - mpi_msb( &W ); MPI_CHK( mpi_shift_r( &A, j + 1 ) ); @@ -1809,7 +1809,7 @@ cleanup: * Prime number generation */ int mpi_gen_prime( mpi *X, int nbits, int dh_flag, - int (*f_rng)(void *), void *p_rng ) + unsigned char (*f_rng)(void *), void *p_rng ) { int ret, k, n; unsigned char *p; @@ -1827,7 +1827,7 @@ int mpi_gen_prime( mpi *X, int nbits, int dh_flag, p = (unsigned char *) X->p; for( k = 0; k < X->n * ciL; k++ ) - *p++ = (unsigned char) f_rng( p_rng ); + *p++ = f_rng( p_rng ); k = mpi_msb( X ); if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); diff --git a/polarssl-0.14.0/library/rsa.c b/polarssl-0.14.0/library/rsa.c index e42aab4..e135e57 100644 --- a/polarssl-0.14.0/library/rsa.c +++ b/polarssl-0.14.0/library/rsa.c @@ -58,7 +58,7 @@ void rsa_init( rsa_context *ctx, * Generate an RSA keypair */ int rsa_gen_key( rsa_context *ctx, - int (*f_rng)(void *), + unsigned char (*f_rng)(void *), void *p_rng, int nbits, int exponent ) { @@ -101,6 +101,7 @@ int rsa_gen_key( rsa_context *ctx, } while( mpi_cmp_int( &G, 1 ) != 0 ); +#if 0 /* * D = E^-1 mod ((P-1)*(Q-1)) * DP = D mod (P - 1) @@ -111,6 +112,7 @@ int rsa_gen_key( rsa_context *ctx, MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); +#endif ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3; @@ -129,6 +131,7 @@ cleanup: #endif +#if 0 /* * Check a public RSA key */ @@ -197,6 +200,7 @@ cleanup: mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL ); return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret ); } +#endif /* * Do an RSA public key operation @@ -295,7 +299,7 @@ cleanup: * Add the message padding, then do an RSA operation */ int rsa_pkcs1_encrypt( rsa_context *ctx, - int (*f_rng)(void *), + unsigned char (*f_rng)(void *), void *p_rng, int mode, int ilen, const unsigned char *input, @@ -323,7 +327,7 @@ int rsa_pkcs1_encrypt( rsa_context *ctx, int rng_dl = 100; do { - *p = (unsigned char) f_rng( p_rng ); + *p = f_rng( p_rng ); } while( *p == 0 && --rng_dl ); // Check if RNG failed to generate data @@ -538,11 +542,11 @@ int rsa_pkcs1_verify( rsa_context *ctx, int hash_id, int hashlen, const unsigned char *hash, - unsigned char *sig ) + const unsigned char *sig ) { int ret, len, siglen; unsigned char *p, c; - unsigned char buf[1024]; + unsigned char buf[256]; siglen = ctx->len; diff --git a/regnual/Makefile b/regnual/Makefile new file mode 100644 index 0000000..154877b --- /dev/null +++ b/regnual/Makefile @@ -0,0 +1,49 @@ +# Makefile for reGNUal + +PROJECT = regnual + +OBJS = regnual.o usb_lld.o sys.o +LDSCRIPT= regnual.ld + +################################### +MCU = cortex-m3 + +TRGT = arm-none-eabi- +CC = $(TRGT)gcc +LD = $(TRGT)ld +OBJCOPY = $(TRGT)objcopy +OBJDUMP = $(TRGT)objdump + +# THUMB-specific options here +TOPT = -mthumb -DTHUMB -mno-thumb-interwork +# Define C warning options here +CWARN = -Wall -Wextra -Wstrict-prototypes +MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd +DEFS = -DFREE_STANDING + +CFLAGS = -O2 -g +CFLAGS += $(CWARN) -I . -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS) + +LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT) + + +#################### + +all: regnual.hex + +regnual.o: regnual.c ../src/sys.h + +regnual.hex: regnual.elf + $(OBJCOPY) -Obinary regnual.elf regnual.bin + $(OBJCOPY) -Oihex regnual.elf regnual.hex + +usb_lld.o: ../src/usb_lld.c + $(CC) $(CFLAGS) -c -o usb_lld.o ../src/usb_lld.c + +regnual.elf: $(OBJS) $(LDSCRIPT) + $(CC) $(LDFLAGS) -o regnual.elf $(OBJS) + +clean: + -rm -f $(OBJS) regnual.elf regnual.hex regnual.bin + +distclean: clean diff --git a/regnual/regnual.c b/regnual/regnual.c new file mode 100644 index 0000000..0d04739 --- /dev/null +++ b/regnual/regnual.c @@ -0,0 +1,355 @@ +/* + * regnual.c -- Firmware installation for STM32F103 Flash ROM + * + * Copyright (C) 2012 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 . + * + */ + +/* + * ReGNUal + */ + +#include "types.h" +#include "usb_lld.h" +#include "sys.h" + +extern void *memset (void *s, int c, size_t n); + +extern void set_led (int); +extern uint8_t _flash_start, _flash_end; +extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len); +extern int flash_protect (void); +extern void nvic_system_reset (void); + + +#define ENDP0_RXADDR (0x40) +#define ENDP0_TXADDR (0x80) + +/* USB Standard Device Descriptor */ +static const uint8_t regnual_device_desc[] = { + 18, /* bLength */ + USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB = 1.1 */ + 0xFF, /* bDeviceClass: VENDOR */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ +#include "../src/usb-vid-pid-ver.c.inc" + 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 */ +}; + +static const uint8_t regnual_config_desc[] = { + 9, + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ + 18, 0, /* wTotalLength: no of returned bytes */ + 1, /* bNumInterfaces: single vender interface */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x00, /* iConfiguration: None */ +#if defined(USB_SELF_POWERED) + 0xC0, /* bmAttributes: self powered */ +#else + 0x80, /* bmAttributes: bus powered */ +#endif + 50, /* MaxPower 100 mA */ + + /* Interface Descriptor */ + 9, + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ + 0, /* bInterfaceNumber: Index of this interface */ + 0, /* Alternate setting for this interface */ + 0, /* bNumEndpoints: None */ + 0xFF, + 0, + 0, + 0, /* string index for interface */ +}; + +static const uint8_t regnual_string_lang_id[] = { + 4, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, + 0x09, 0x04 /* LangID = 0x0409: US-English */ +}; + +#include "../src/usb-strings.c.inc" + +static const uint8_t regnual_string_serial[] = { + 8*2+2, + USB_STRING_DESCRIPTOR_TYPE, + /* FSIJ-0.0 */ + 'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0, + '0', 0, '.', 0, '0', 0, +}; + +const struct Descriptor device_desc = { + regnual_device_desc, + sizeof (regnual_device_desc) +}; + +const struct Descriptor config_desc = { + regnual_config_desc, + sizeof (regnual_config_desc) +}; + +const struct Descriptor string_descs[] = { + {regnual_string_lang_id, sizeof (regnual_string_lang_id)}, + {gnukStringVendor, sizeof (gnukStringVendor)}, + {gnukStringProduct, sizeof (gnukStringProduct)}, + {regnual_string_serial, sizeof (regnual_string_serial)}, +}; + +#define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor)) + +static void +regnual_device_reset (void) +{ + /* Set DEVICE as not configured */ + usb_lld_set_configuration (0); + + /* Current Feature initialization */ + usb_lld_set_feature (config_desc.Descriptor[7]); + + usb_lld_reset (); + + /* Initialize Endpoint 0 */ + usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, + 64); +} + +#define USB_REGNUAL_MEMINFO 0 +#define USB_REGNUAL_SEND 1 +#define USB_REGNUAL_RESULT 2 +#define USB_REGNUAL_FLASH 3 +#define USB_REGNUAL_PROTECT 4 +#define USB_REGNUAL_FINISH 5 + +static uint8_t mem[256]; +static uint32_t result; + +static const uint8_t *const mem_info[] = { &_flash_start, &_flash_end, }; + + +static uint32_t rbit (uint32_t v) +{ + uint32_t r; + + asm ("rbit %0, %1" : "=r" (r) : "r" (v)); + return r; +} + +static uint32_t fetch (int i) +{ + uint32_t v; + + v = *(uint32_t *)(&mem[i*4]); + return rbit (v); +} + +struct CRC { + __IO uint32_t DR; + __IO uint8_t IDR; + uint8_t RESERVED0; + uint16_t RESERVED1; + __IO uint32_t CR; +}; + +#define CRC_CR_RESET 0x01 +static uint32_t calc_crc32 (void) +{ + struct CRC *CRC = (struct CRC *)0x40023000; + int i; + + CRC->CR = CRC_CR_RESET; + + for (i = 0; i < 256/4; i++) + CRC->DR = fetch (i); + + return rbit (CRC->DR); +} + + +static void regnual_ctrl_write_finish (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, + uint16_t len) +{ + uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); + + if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req)) + { + if (req_no == USB_REGNUAL_SEND && value == 0) + result = calc_crc32 (); + else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0) + { + uint32_t dst_addr = (0x08000000 + value * 0x100); + + result = flash_write (dst_addr, mem, 256); + } + else if (req_no == USB_REGNUAL_PROTECT && len == 0 + && value == 0 && index == 0) + result = flash_protect (); + else if (req_no == USB_REGNUAL_FINISH && len == 0 + && value == 0 && index == 0) + nvic_system_reset (); + } +} + +static int +regnual_setup (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, uint16_t len) +{ + uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); + + if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)) + { + if (USB_SETUP_GET (req)) + { + if (req_no == USB_REGNUAL_MEMINFO) + { + usb_lld_set_data_to_send (mem_info, sizeof (mem_info)); + return USB_SUCCESS; + } + else if (req_no == USB_REGNUAL_RESULT) + { + usb_lld_set_data_to_send (&result, sizeof (uint32_t)); + return USB_SUCCESS; + } + } + else /* SETUP_SET */ + { + if (req_no == USB_REGNUAL_SEND) + { + if (value != 0 || index + len > 256) + return USB_UNSUPPORT; + + if (index + len < 256) + memset (mem + index + len, 0xff, 256 - (index + len)); + + usb_lld_set_data_to_recv (mem + index, len); + return USB_SUCCESS; + } + else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0) + { + uint32_t dst_addr = (0x08000000 + value * 0x100); + + if (dst_addr + 256 <= (uint32_t)&_flash_end) + return USB_SUCCESS; + } + else if (req_no == USB_REGNUAL_PROTECT && len == 0 + && value == 0 && index == 0) + return USB_SUCCESS; + else if (req_no == USB_REGNUAL_FINISH && len == 0 + && value == 0 && index == 0) + return USB_SUCCESS; + } + } + + return USB_UNSUPPORT; +} + +static int +regnual_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value) +{ + (void)index; + if (desc_type == DEVICE_DESCRIPTOR) + { + usb_lld_set_data_to_send (device_desc.Descriptor, + device_desc.Descriptor_Size); + return USB_SUCCESS; + } + else if (desc_type == CONFIG_DESCRIPTOR) + { + usb_lld_set_data_to_send (config_desc.Descriptor, + config_desc.Descriptor_Size); + return USB_SUCCESS; + } + else if (desc_type == STRING_DESCRIPTOR) + { + uint8_t desc_index = value & 0xff; + + if (desc_index < NUM_STRING_DESC) + { + usb_lld_set_data_to_send (string_descs[desc_index].Descriptor, + string_descs[desc_index].Descriptor_Size); + return USB_SUCCESS; + } + } + + return USB_UNSUPPORT; +} + +static int regnual_usb_event (uint8_t event_type, uint16_t value) +{ + (void)value; + + switch (event_type) + { + case USB_EVENT_ADDRESS: + case USB_EVENT_CONFIG: + return USB_SUCCESS; + default: + break; + } + + return USB_UNSUPPORT; +} + +static int regnual_interface (uint8_t cmd, uint16_t interface, uint16_t alt) +{ + (void)cmd; (void)interface; (void)alt; + return USB_UNSUPPORT; +} + +const struct usb_device_method Device_Method = { + regnual_device_reset, + regnual_ctrl_write_finish, + regnual_setup, + regnual_get_descriptor, + regnual_usb_event, + regnual_interface, +}; + +static void wait (int count) +{ + int i; + + for (i = 0; i < count; i++) + asm volatile ("" : : "r" (i) : "memory"); +} + +#define WAIT 2400000 + +int +main (int argc, char *argv[]) +{ + (void)argc; (void)argv; + + set_led (0); + + usb_lld_init (regnual_config_desc[7]); + + while (1) + { + set_led (1); + wait (WAIT); + set_led (0); + wait (WAIT); + } +} diff --git a/regnual/regnual.ld b/regnual/regnual.ld new file mode 100644 index 0000000..c470c1d --- /dev/null +++ b/regnual/regnual.ld @@ -0,0 +1,98 @@ +/* + * ST32F103 memory setup. + */ +__main_stack_size__ = 0x0400; +__process_stack_size__ = 0x0200; +__stacks_total_size__ = __main_stack_size__ + __process_stack_size__; + +MEMORY +{ + ram0 : org = 0x20000000, len = 0x1400 + ram1 : org = 0x20001400, len = 20k - 0x1400 +} + +vector = 0x08000000; +_flash_start = 0x08001000; +_flash_end = 0x08020000; + +__ram_start__ = ORIGIN(ram0); +__ram_size__ = 20k; +__ram_end__ = __ram_start__ + __ram_size__; + +SECTIONS +{ + . = 0; + + .bss : + { + _bss_start = .; + *(.bss) + . = ALIGN(4); + *(.bss.*) + . = ALIGN(4); + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > ram0 + + .text : ALIGN(16) SUBALIGN(16) + { + _text = .; + KEEP(*(.vectors)) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.glue_7t) + *(.glue_7) + *(.gcc*) + } > ram1 + + .ctors : + { + PROVIDE(_ctors_start_ = .); + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + PROVIDE(_ctors_end_ = .); + } > ram1 + + .dtors : + { + PROVIDE(_dtors_start_ = .); + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + PROVIDE(_dtors_end_ = .); + } > ram1 + + .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} + + __exidx_start = .; + .ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > ram1 + __exidx_end = .; + + .eh_frame_hdr : {*(.eh_frame_hdr)} + + .eh_frame : ONLY_IF_RO {*(.eh_frame)} + + . = ALIGN(4); + _etext = .; + _textdata = _etext; + + .data : + { + _data = .; + *(.data) + . = ALIGN(4); + *(.data.*) + . = ALIGN(4); + *(.ramtext) + . = ALIGN(4); + _edata = .; + } > ram1 + + PROVIDE(end = .); + _end = .; +} + +__heap_base__ = _end; +__heap_end__ = __ram_end__ - __stacks_total_size__; diff --git a/regnual/sys.c b/regnual/sys.c new file mode 100644 index 0000000..702e4c8 --- /dev/null +++ b/regnual/sys.c @@ -0,0 +1,60 @@ +#include "types.h" + +static void fatal (void) +{ + for (;;); +} + +static void none (void) +{ +} + +/* Note: it is not reset */ +static __attribute__ ((naked)) +void entry (void) +{ + asm volatile ("ldr r0, =__ram_end__\n\t" + "ldr r1, =__main_stack_size__\n\t" + "sub r0, r0, r1\n\t" + "mov sp, r0\n\t" + "mov r0, #0\n\t" + "ldr r1, =_bss_start\n\t" + "ldr r2, =_bss_end\n" + "0:\n\t" + "str r0, [r1], #4\n\t" + "cmp r2, r1\n\t" + "bhi 0b\n\t" + "cpsie i\n\t" /* Enable interrupts */ + "mov r0, #0\n\t" + "mov r1, r0\n\t" + "bl main\n" + "1:\n\t" + "b 1b\n" + : /* no output */ : /* no input */ : "memory"); +} + +typedef void (*handler)(void); +extern uint8_t __ram_end__; +extern void usb_interrupt_handler (void); + +handler vector_table[] __attribute__ ((section(".vectors"))) = { + (handler)&__ram_end__, + entry, + fatal, /* nmi */ + fatal, /* hard fault */ + /* 10 */ + fatal, /* mem manage */ + fatal, /* bus fault */ + fatal, /* usage fault */ + none, + /* 20 */ + none, none, none, none, none, none, none, none, + /* 40 */ + none, none, none, none, none, none, none, none, + /* 60 */ + none, none, none, none, none, none, none, none, + /* 80 */ + none, none, none, none, + /* 90 */ + usb_interrupt_handler, +}; diff --git a/regnual/types.h b/regnual/types.h new file mode 100644 index 0000000..ed28a12 --- /dev/null +++ b/regnual/types.h @@ -0,0 +1,12 @@ +typedef unsigned long size_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#define TRUE 1 +#define FALSE 0 + +#define NULL 0 + +#define __IO volatile diff --git a/src/Makefile.in b/src/Makefile.in index c8b0827..fb38a33 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -3,9 +3,6 @@ BOARD_DIR=@BOARD_DIR@ @PINPAD_MAKE_OPTION@ @DEBUG_MAKE_OPTION@ -ifneq ($(ENABLE_DEBUG),) -ENABLE_VCOMPORT=1 -endif ############################################################################## # Build global options @@ -14,7 +11,7 @@ endif # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 + USE_OPT = -O3 -Os -ggdb -fomit-frame-pointer -falign-functions=16 endif # C++ specific options here (added to USE_OPT). @@ -70,8 +67,6 @@ include $(CHIBIOS)/os/hal/platforms/STM32/platform.mk include $(CHIBIOS)/os/hal/hal.mk include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/port.mk include $(CHIBIOS)/os/kernel/kernel.mk -include stmusb.mk -include vcomport.mk include crypt.mk # C sources that can be compiled in ARM or THUMB mode depending on the global @@ -81,17 +76,15 @@ CSRC = $(PORTSRC) \ $(HALSRC) \ $(PLATFORMSRC) \ $(BOARDSRC) \ - ../boards/common/hw_config.c \ $(BOARD_DIR)/board.c \ $(CHIBIOS)/os/various/evtimer.c \ $(CHIBIOS)/os/various/syscalls.c \ - $(STMUSBSRC) \ - $(VCOMSRC) \ $(CRYPTSRC) \ main.c usb_lld.c \ - usb_desc.c usb_prop.c \ - usb-icc.c openpgp.c ac.c openpgp-do.c flash.c hardclock.c \ - random.c neug.c bn.c modp256.c jpc.c mod.c ec_p256.c + usb_desc.c usb_ctrl.c \ + usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \ + bn.c modp256.c jpc.c mod.c ec_p256.c \ + random.c neug.c sys.c ifneq ($(ENABLE_DEBUG),) CSRC += debug.c @@ -101,11 +94,15 @@ ifneq ($(ENABLE_PINPAD),) CSRC += pin-$(ENABLE_PINPAD).c endif +ifeq ($(ENABLE_PINPAD),dnd) +CSRC += usb-msc.c +endif + # List ASM source files here ASMSRC = $(PORTASM) \ $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s -INCDIR = $(CRYPTINCDIR) $(STMUSBINCDIR) $(VCOMDIR) \ +INCDIR = $(CRYPTINCDIR) \ $(PORTINC) $(KERNINC) $(TESTINC) \ $(HALINC) $(PLATFORMINC) ../boards/common $(BOARD_DIR) \ $(CHIBIOS)/os/various @@ -179,7 +176,7 @@ DLIBS = # # List all user C define here, like -D_DEBUG=1 -UDEFS = +UDEFS = @KEYGEN_SUPPORT@ # Define ASM defines here UADEFS = @@ -197,14 +194,8 @@ ULIBS = # End of user defines ############################################################################## -ifeq ($(USE_FWLIB),yes) - include $(CHIBIOS)/ext/stm32lib/stm32lib.mk - CSRC += $(STM32SRC) - INCDIR += $(STM32INC) - USE_OPT += -DUSE_STDPERIPH_DRIVER -endif - include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk +MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd distclean: clean - -rm -f Makefile gnuk.ld config.h + -rm -f Makefile gnuk.ld config.h *.inc diff --git a/src/ac.c b/src/ac.c index f6300d5..86679ff 100644 --- a/src/ac.c +++ b/src/ac.c @@ -1,7 +1,7 @@ /* * ac.c -- Check access condition * - * Copyright (C) 2010 Free Software Initiative of Japan + * Copyright (C) 2010, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -24,9 +24,7 @@ #include "config.h" #include "ch.h" #include "gnuk.h" - -#include "polarssl/config.h" -#include "polarssl/sha1.h" +#include "sha256.h" uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */ @@ -57,11 +55,11 @@ ac_reset_other (void) } int -verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known, +verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known, const uint8_t *ks_pw1) { int pw_len; - int r; + int r1, r2; uint8_t keystring[KEYSTRING_MD_SIZE]; if (gpg_pw_locked (PW_ERR_PW1)) @@ -75,7 +73,7 @@ verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known, || strncmp ((const char *)pw, OPENPGP_CARD_INITIAL_PW1, pw_len)) goto failure; else - goto success; + goto success_one_step; } else pw_len = ks_pw1[0]; @@ -88,15 +86,28 @@ verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known, return -1; } - sha1 (pw, pw_len, keystring); - if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring)) - < 0) - goto failure; - else if (r == 0) - if (memcmp (ks_pw1+1, keystring, KEYSTRING_MD_SIZE) != 0) + success_one_step: + s2k (BY_USER, pw, pw_len, keystring); + if (access == AC_PSO_CDS_AUTHORIZED) + { + r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring); + r2 = 0; + } + else + { + r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring); + r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring); + } + + if (r1 < 0 || r2 < 0) + { + gpg_pw_increment_err_counter (PW_ERR_PW1); + return -1; + } + else if (r1 == 0 && r2 == 0) + if (ks_pw1 != NULL && memcmp (ks_pw1+1, keystring, KEYSTRING_MD_SIZE) != 0) goto failure; - success: gpg_pw_reset_err_counter (PW_ERR_PW1); return pw_len; } @@ -113,7 +124,7 @@ verify_pso_cds (const uint8_t *pw, int pw_len) DEBUG_INFO ("verify_pso_cds\r\n"); DEBUG_BYTE (pw_len); - r = verify_user_0 (pw, pw_len, pw_len, ks_pw1); + r = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, pw_len, pw_len, ks_pw1); if (r > 0) auth_status |= AC_PSO_CDS_AUTHORIZED; return r; @@ -122,29 +133,16 @@ verify_pso_cds (const uint8_t *pw, int pw_len) int verify_other (const uint8_t *pw, int pw_len) { - int r1, r2; - uint8_t keystring[KEYSTRING_MD_SIZE]; + const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); + int r; DEBUG_INFO ("verify_other\r\n"); + DEBUG_BYTE (pw_len); - if (gpg_pw_locked (PW_ERR_PW1)) - return 0; - - sha1 (pw, pw_len, keystring); - if ((r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring)) < 0 - || (r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, - keystring)) < 0) - { - gpg_pw_increment_err_counter (PW_ERR_PW1); - return -1; - } - else if (r1 == 0 && r2 == 0) - /* No key is available. Fail even if password can match. */ - return -1; - - gpg_pw_reset_err_counter (PW_ERR_PW1); - auth_status |= AC_OTHER_AUTHORIZED; - return 1; + r = verify_user_0 (AC_OTHER_AUTHORIZED, pw, pw_len, pw_len, ks_pw1); + if (r > 0) + auth_status |= AC_OTHER_AUTHORIZED; + return r; } /* @@ -161,28 +159,27 @@ static void calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len, uint8_t md[KEYSTRING_MD_SIZE]) { - sha1_context sha1_ctx; + sha256_context sha256_ctx; - sha1_starts (&sha1_ctx); + sha256_start (&sha256_ctx); while (count > pw_len + 8) { - sha1_update (&sha1_ctx, salt, 8); - sha1_update (&sha1_ctx, pw, pw_len); + sha256_update (&sha256_ctx, salt, 8); + sha256_update (&sha256_ctx, pw, pw_len); count -= pw_len + 8; } - if (count < 8) - sha1_update (&sha1_ctx, salt, count); + if (count <= 8) + sha256_update (&sha256_ctx, salt, count); else { - sha1_update (&sha1_ctx, salt, 8); + sha256_update (&sha256_ctx, salt, 8); count -= 8; - sha1_update (&sha1_ctx, pw, count); + sha256_update (&sha256_ctx, pw, count); } - sha1_finish (&sha1_ctx, md); - memset (&sha1_ctx, 0, sizeof (sha1_ctx)); + sha256_finish (&sha256_ctx, md); } uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE]; @@ -205,7 +202,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) return 0; pw_len = pw3_keystring[0]; - if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len) + if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len > buf_len) goto failure; salt = &pw3_keystring[1]; @@ -230,7 +227,8 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) if (ks_pw1 != NULL) { /* empty PW3, but PW1 exists */ - int r = verify_user_0 (pw, buf_len, pw_len_known, ks_pw1); + int r = verify_user_0 (AC_PSO_CDS_AUTHORIZED, + pw, buf_len, pw_len_known, ks_pw1); if (r > 0) admin_authorized = BY_USER; @@ -282,7 +280,7 @@ verify_admin (const uint8_t *pw, int pw_len) if (r <= 0) return r; - sha1 (pw, pw_len, keystring_md_pw3); + s2k (admin_authorized, pw, pw_len, keystring_md_pw3); auth_status |= AC_ADMIN_AUTHORIZED; return 1; } @@ -292,6 +290,7 @@ ac_reset_admin (void) { memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE); auth_status &= ~AC_ADMIN_AUTHORIZED; + admin_authorized = 0; } void @@ -302,4 +301,5 @@ ac_fini (void) gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION); gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION); auth_status = AC_NONE_AUTHORIZED; + admin_authorized = 0; } diff --git a/src/call-rsa.c b/src/call-rsa.c index 7769ee8..1772e29 100644 --- a/src/call-rsa.c +++ b/src/call-rsa.c @@ -1,7 +1,7 @@ /* * call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol * - * Copyright (C) 2010 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -25,10 +25,13 @@ #include "config.h" #include "ch.h" #include "gnuk.h" +#include "openpgp.h" #include "polarssl/config.h" #include "polarssl/rsa.h" -#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */ +#define RSA_SIGNATURE_LENGTH KEY_CONTENT_LEN + /* 256 byte == 2048-bit */ + /* 128 byte == 1024-bit */ static rsa_context rsa_ctx; @@ -43,11 +46,13 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len, mpi_init (&P1, &Q1, &H, NULL); rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); - rsa_ctx.len = 2048 / 8; - mpi_read_string (&rsa_ctx.E, 16, "10001"); + rsa_ctx.len = KEY_CONTENT_LEN; + mpi_lset (&rsa_ctx.E, 0x10001); mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2); - mpi_read_binary (&rsa_ctx.Q, &kd->data[128], rsa_ctx.len / 2); + mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], rsa_ctx.len / 2); +#if 0 /* Using CRT, we don't use N */ mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); +#endif mpi_sub_int (&P1, &rsa_ctx.P, 1); mpi_sub_int (&Q1, &rsa_ctx.Q, 1); mpi_mul_mpi (&H, &P1, &Q1); @@ -58,17 +63,6 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len, mpi_free (&P1, &Q1, &H, NULL); DEBUG_INFO ("RSA sign..."); -#if 0 - if ((r = rsa_check_privkey (&rsa_ctx)) == 0) - DEBUG_INFO ("ok..."); - else - { - DEBUG_INFO ("failed.\r\n"); - DEBUG_SHORT (r); - rsa_free (&rsa_ctx); - return r; - } -#endif r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW, msg_len, raw_message, temp); @@ -82,31 +76,32 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len, } else { - res_APDU[RSA_SIGNATURE_LENGTH] = 0x90; - res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00; - res_APDU_size = RSA_SIGNATURE_LENGTH + 2; + res_APDU_size = RSA_SIGNATURE_LENGTH; DEBUG_INFO ("done.\r\n"); + GPG_SUCCESS (); return 0; } } +/* + * LEN: length in byte + */ const uint8_t * modulus_calc (const uint8_t *p, int len) { mpi P, Q, N; uint8_t *modulus; - (void)len; /* 2048-bit assumed */ - modulus = malloc (2048 / 8); + modulus = malloc (len); if (modulus == NULL) return NULL; mpi_init (&P, &Q, &N, NULL); - mpi_read_binary (&P, p, 2048 / 8 / 2); - mpi_read_binary (&Q, p + 128, 2048 / 8 / 2); + mpi_read_binary (&P, p, len / 2); + mpi_read_binary (&Q, p + len / 2, len / 2); mpi_mul_mpi (&N, &P, &Q); - mpi_write_binary (&N, modulus, 2048 / 8); + mpi_write_binary (&N, modulus, len); mpi_free (&P, &Q, &N, NULL); return modulus; } @@ -134,10 +129,13 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len, rsa_ctx.len = msg_len; DEBUG_WORD (msg_len); - mpi_read_string (&rsa_ctx.E, 16, "10001"); - mpi_read_binary (&rsa_ctx.P, &kd->data[0], 2048 / 8 / 2); - mpi_read_binary (&rsa_ctx.Q, &kd->data[128], 2048 / 8 / 2); + mpi_lset (&rsa_ctx.E, 0x10001); + mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2); + mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], + KEY_CONTENT_LEN / 2); +#if 0 /* Using CRT, we don't use N */ mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q); +#endif mpi_sub_int (&P1, &rsa_ctx.P, 1); mpi_sub_int (&Q1, &rsa_ctx.Q, 1); mpi_mul_mpi (&H, &P1, &Q1); @@ -148,21 +146,9 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len, mpi_free (&P1, &Q1, &H, NULL); DEBUG_INFO ("RSA decrypt ..."); -#if 0 - /* This consume some memory */ - if ((r = rsa_check_privkey (&rsa_ctx)) == 0) - DEBUG_INFO ("ok..."); - else - { - DEBUG_INFO ("failed.\r\n"); - DEBUG_SHORT (r); - rsa_free (&rsa_ctx); - return r; - } -#endif r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len, - input, output, MAX_RES_APDU_SIZE - 2); + input, output, MAX_RES_APDU_DATA_SIZE); rsa_free (&rsa_ctx); if (r < 0) { @@ -172,10 +158,71 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len, } else { - res_APDU[output_len] = 0x90; - res_APDU[output_len+1] = 0x00; - res_APDU_size = output_len + 2; + res_APDU_size = output_len; DEBUG_INFO ("done.\r\n"); + GPG_SUCCESS (); return 0; } } + +int +rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig) +{ + int r; + + rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); + rsa_ctx.len = KEY_CONTENT_LEN; + mpi_lset (&rsa_ctx.E, 0x10001); + mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN); + + DEBUG_INFO ("RSA verify..."); + + r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA256, 32, hash, sig); + + rsa_free (&rsa_ctx); + if (r < 0) + { + DEBUG_INFO ("fail:"); + DEBUG_SHORT (r); + return r; + } + else + { + DEBUG_INFO ("verified.\r\n"); + return 0; + } +} + +#define RSA_EXPONENT 0x10001 + +#ifdef KEYGEN_SUPPORT +const uint8_t * +rsa_genkey (void) +{ + int r; + uint8_t index = 0; + uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2); + uint8_t *p = p_q_modulus; + uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2; + uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN; + + if (p_q_modulus == NULL) + return NULL; + + rsa_init (&rsa_ctx, RSA_PKCS_V15, 0); + r = rsa_gen_key (&rsa_ctx, random_byte, &index, + KEY_CONTENT_LEN * 8, RSA_EXPONENT); + if (r < 0) + { + free (p_q_modulus); + rsa_free (&rsa_ctx); + return NULL; + } + + mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2); + mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2); + mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN); + rsa_free (&rsa_ctx); + return p_q_modulus; +} +#endif diff --git a/src/config.h.in b/src/config.h.in index 23fe05d..cb61d1b 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -5,3 +5,5 @@ @DFU_DEFINE@ @PINPAD_DEFINE@ @PINPAD_MORE_DEFINE@ +@CERTDO_DEFINE@ +#define FLASH_PAGE_SIZE @FLASH_PAGE_SIZE@ diff --git a/src/configure b/src/configure index dea3fa4..6252c61 100755 --- a/src/configure +++ b/src/configure @@ -3,7 +3,7 @@ # # This file is *NOT* generated by GNU Autoconf, but written by NIIBE Yutaka # -# Copyright (C) 2010, 2011 Free Software Initiative of Japan +# Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan # # This file is a part of Gnuk, a GnuPG USB Token implementation. # Gnuk is free software: you can redistribute it and/or modify it @@ -21,17 +21,14 @@ # Default settings help=no +vidpid=none target=OLIMEX_STM32_H103 verbose=no with_dfu=default debug=no pinpad=no - -# check /dev/random -if test ! -e /dev/random; then - echo "/dev/random is required." >&2 - exit 1 -fi +certdo=no +keygen=no # Process each option for option; do @@ -43,20 +40,28 @@ for option; do case $option in -h | --help) help=yes ;; - --target=*) - target=$optarg ;; -v | --verbose) verbose=yes ;; + --vidpid=*) + vidpid=$optarg ;; + --target=*) + target=$optarg ;; --enable-debug) debug=yes ;; --disable-debug) debug=no ;; - --enable-pinpad) - pinpad=yes ;; --enable-pinpad=*) pinpad=$optarg ;; --disable-pinpad) pinpad=no ;; + --enable-certdo) + certdo=yes ;; + --disable-certdo) + certdo=no ;; + --enable-keygen) + keygen=yes ;; + --disable-keygen) + keygen=no ;; --with-dfu) with_dfu=yes ;; --without-dfu) @@ -77,6 +82,7 @@ Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit [no] + --vidpid=VID:PID specify vendor/product ID [] --target=TARGET specify target [OLIMEX_STM32_H103] supported targes are: OLIMEX_STM32_H103 @@ -85,14 +91,22 @@ Configuration: STBEE_MINI STM8S_DISCOVERY STBEE + FST_01 --enable-debug debug with virtual COM port [no] --enable-pinpad={cir,dial} - PIN input device support [no] + PIN entry support [no] + --enable-certdo support CERT.3 data object [no] + --enable-keygen support key generation [no] --with-dfu build image for DFU [] EOF exit 0 fi +if test "$vidpid" = "none"; then + echo "Please specify Vendor ID and Product ID by --vidpid option." + exit 1 +fi + BOARD_DIR=../boards/$target if test -d $BOARD_DIR; then echo "Configured for target: $target" @@ -147,6 +161,7 @@ if test "$with_dfu" = "yes"; then FLASH_SIZE=`expr $FLASH_SIZE - 12` DFU_DEFINE="#define DFU_SUPPORT 1" else + with_dfu=no echo "Configured for bare system (no-DFU)" ORIGIN=0x08000000 DFU_DEFINE="#undef DFU_SUPPORT" @@ -158,11 +173,6 @@ if test "$pinpad" = "no"; then PINPAD_DEFINE="#undef PINPAD_SUPPORT" PINPAD_MORE_DEFINE="" echo "PIN pad option disabled" -elif test "$pinpad" = "yes"; then - PINPAD_MAKE_OPTION="ENABLE_PINPAD=cir" - PINPAD_DEFINE="#define PINPAD_SUPPORT 1" - PINPAD_MORE_DEFINE="#define PINPAD_CIR_SUPPORT 1" - echo "PIN pad option enabled (cir)" else PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad" PINPAD_DEFINE="#define PINPAD_SUPPORT 1" @@ -170,16 +180,93 @@ else echo "PIN pad option enabled ($pinpad)" fi +# --enable-certdo option +if test "$certdo" = "yes"; then + CERTDO_DEFINE="#define CERTDO_SUPPORT 1" + echo "CERT.3 Data Object is supported" +else + CERTDO_DEFINE="#undef CERTDO_SUPPORT" + echo "CERT.3 Data Object is NOT supported" +fi + +# --enable-keygen option +if test "$keygen" = "yes"; then + KEYGEN_SUPPORT="-DKEYGEN_SUPPORT" + echo "Key generation on device is supported" +else + KEYGEN_SUPPORT="" + echo "Key generation on device is NOT supported" +fi + +REVISION=`git describe --dirty="-modified"` +CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:keygen=$keygen" + +if !(IFS=" " + while read VIDPID VERSION PRODUCT VENDOR; do + if test "$vidpid" = "$VIDPID"; then + (echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\n 0x\4, 0x\3, /* idProduct */%p" + echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p" + ) > usb-vid-pid-ver.c.inc + (echo 'static const uint8_t gnukStringVendor[] = {' + echo " ${#VENDOR}*2+2, /* bLength */" + echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */" + echo " /* Manufacturer: \"$VENDOR\" */" + echo $VENDOR | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p" + echo '};' + echo + echo 'static const uint8_t gnukStringProduct[] = {' + echo " ${#PRODUCT}*2+2, /* bLength */" + echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */" + echo " /* Product name: \"$PRODUCT\" */" + echo $PRODUCT | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p" + echo '};' + echo + echo '#ifdef USB_STRINGS_FOR_GNUK' + echo 'static const uint8_t gnuk_revision_detail[] = {' + echo " ${#REVISION}*2+2, /* bLength */" + echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */" + echo " /* revision detail: \"$REVISION\" */" + echo $REVISION | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p" + echo '};' + echo + echo 'static const uint8_t gnuk_config_options[] = {' + echo " ${#CONFIG}*2+2, /* bLength */" + echo " USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */" + echo " /* configure options: \"$CONFIG\" */" + echo $CONFIG | sed -n -e "s/\(........\)/\1\n/gp" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "s/ $//p" + echo '};' + echo '#endif' + ) >usb-strings.c.inc + exit 0 + fi + done; exit 1) < ../GNUK_USB_DEVICE_ID +then + echo "Please specify valid Vendor ID and Product ID." + echo "Check ../GNUK_USB_DEVICE_ID." + exit 1 +fi + sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \ -e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \ -e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \ + -e "s%@KEYGEN_SUPPORT@%$KEYGEN_SUPPORT%" \ < Makefile.in > Makefile -sed -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \ - -e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ +if test "$certdo" = "yes"; then + sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \ + -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \ + -e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ < gnuk.ld.in > gnuk.ld +else + sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \ + -e "s/@ORIGIN@/$ORIGIN/" -e "s/@FLASH_SIZE@/$FLASH_SIZE/" \ + -e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ + < gnuk.ld.in > gnuk.ld +fi sed -e "s/@DEBUG_DEFINE@/$DEBUG_DEFINE/" \ + -e "s/@DFU_DEFINE@/$DFU_DEFINE/" \ -e "s/@PINPAD_DEFINE@/$PINPAD_DEFINE/" \ -e "s/@PINPAD_MORE_DEFINE@/$PINPAD_MORE_DEFINE/" \ - -e "s/@DFU_DEFINE@/$DFU_DEFINE/" \ + -e "s/@CERTDO_DEFINE@/$CERTDO_DEFINE/" \ + -e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \ < config.h.in > config.h exit 0 diff --git a/src/crypt.mk b/src/crypt.mk index f0b7ea5..e9c530d 100644 --- a/src/crypt.mk +++ b/src/crypt.mk @@ -1,6 +1,6 @@ CRYPTDIR = ../polarssl-0.14.0 CRYPTSRCDIR = $(CRYPTDIR)/library CRYPTINCDIR = $(CRYPTDIR)/include -CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/sha1.c \ +CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c \ $(CRYPTSRCDIR)/aes.c \ - call-rsa.c + sha256.c call-rsa.c diff --git a/src/flash.c b/src/flash.c index 2e1720a..0f13b62 100644 --- a/src/flash.c +++ b/src/flash.c @@ -1,7 +1,7 @@ /* * flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM * - * Copyright (C) 2010, 2011 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -32,108 +32,9 @@ #include "config.h" #include "ch.h" #include "hal.h" +#include "sys.h" #include "gnuk.h" -#define FLASH_KEY1 0x45670123UL -#define FLASH_KEY2 0xCDEF89ABUL - -enum flash_status -{ - FLASH_BUSY = 1, - FLASH_ERROR_PG, - FLASH_ERROR_WRP, - FLASH_COMPLETE, - FLASH_TIMEOUT -}; - -void -flash_unlock (void) -{ - FLASH->KEYR = FLASH_KEY1; - FLASH->KEYR = FLASH_KEY2; -} - -static int -flash_get_status (void) -{ - int status; - - if ((FLASH->SR & FLASH_SR_BSY) != 0) - status = FLASH_BUSY; - else if ((FLASH->SR & FLASH_SR_PGERR) != 0) - status = FLASH_ERROR_PG; - else if((FLASH->SR & FLASH_SR_WRPRTERR) != 0 ) - status = FLASH_ERROR_WRP; - else - status = FLASH_COMPLETE; - - return status; -} - -static int -flash_wait_for_last_operation (uint32_t timeout) -{ - int status; - - do - if (--timeout == 0) - return FLASH_TIMEOUT; - else - status = flash_get_status (); - while (status == FLASH_BUSY); - - return status; -} - -#define FLASH_PROGRAM_TIMEOUT 0x00010000 -#define FLASH_ERASE_TIMEOUT 0x01000000 - -static int -flash_program_halfword (uint32_t addr, uint16_t data) -{ - int status; - - status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); - - chSysLock (); - if (status == FLASH_COMPLETE) - { - FLASH->CR |= FLASH_CR_PG; - - *(volatile uint16_t *)addr = data; - - status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); - if (status != FLASH_TIMEOUT) - FLASH->CR &= ~FLASH_CR_PG; - } - chSysUnlock (); - - return status; -} - -static int -flash_erase_page (uint32_t addr) -{ - int status; - - status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); - - chSysLock (); - if (status == FLASH_COMPLETE) - { - FLASH->CR |= FLASH_CR_PER; - FLASH->AR = addr; - FLASH->CR |= FLASH_CR_STRT; - - status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); - if (status != FLASH_TIMEOUT) - FLASH->CR &= ~FLASH_CR_PER; - } - chSysUnlock () - - return status; -} - /* * Flash memory map * @@ -145,7 +46,7 @@ flash_erase_page (uint32_t addr) * .data * _bss_start * .bss - * _end + * _end * * ch_certificate_startp * <2048 bytes> @@ -154,14 +55,11 @@ flash_erase_page (uint32_t addr) * _keystore_pool * 1.5-KiB Key store (512-byte (p, q and N) key-store * 3) */ +#define KEY_SIZE 512 /* P, Q and N */ + #define FLASH_DATA_POOL_HEADER_SIZE 2 -#if defined(STM32F10X_HD) -#define FLASH_PAGE_SIZE 2048 -#else -#define FLASH_PAGE_SIZE 1024 -#endif #define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2) -#define FLASH_KEYSTORE_SIZE (512*3) +#define FLASH_KEYSTORE_SIZE (KEY_SIZE*3) static const uint8_t *data_pool; extern uint8_t _keystore_pool; @@ -200,7 +98,7 @@ flash_init (void) /* Seek empty keystore */ p = &_keystore_pool; while (*p != 0xff || *(p+1) != 0xff) - p += 512; + p += KEY_SIZE; keystore = p; @@ -294,14 +192,14 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len) addr = (uint32_t)p; hw = nr | (len << 8); - if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + if (flash_program_halfword (addr, hw) != 0) flash_warning ("DO WRITE ERROR"); addr += 2; for (i = 0; i < len/2; i++) { hw = data[i*2] | (data[i*2+1]<<8); - if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + if (flash_program_halfword (addr, hw) != 0) flash_warning ("DO WRITE ERROR"); addr += 2; } @@ -309,9 +207,8 @@ flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len) if ((len & 1)) { hw = data[i*2] | 0xff00; - if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + if (flash_program_halfword (addr, hw) != 0) flash_warning ("DO WRITE ERROR"); - addr += 2; } } @@ -360,20 +257,19 @@ flash_do_release (const uint8_t *do_data) /* Fill zero for content and pad */ for (i = 0; i < len/2; i ++) { - if (flash_program_halfword (addr, 0) != FLASH_COMPLETE) + if (flash_program_halfword (addr, 0) != 0) flash_warning ("fill-zero failure"); addr += 2; } if ((len & 1)) { - if (flash_program_halfword (addr, 0) != FLASH_COMPLETE) + if (flash_program_halfword (addr, 0) != 0) flash_warning ("fill-zero pad failure"); - addr += 2; } /* Fill 0x0000 for "tag_number and length" word */ - if (flash_program_halfword (addr_tag, 0) != FLASH_COMPLETE) + if (flash_program_halfword (addr_tag, 0) != 0) flash_warning ("fill-zero tag_nr failure"); } @@ -385,7 +281,7 @@ flash_key_alloc (void) if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE) return NULL; - keystore += 512; + keystore += KEY_SIZE; return k; } @@ -401,7 +297,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data, for (i = 0; i < KEY_CONTENT_LEN/2; i ++) { hw = key_data[i*2] | (key_data[i*2+1]<<8); - if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + if (flash_program_halfword (addr, hw) != 0) return -1; addr += 2; } @@ -409,7 +305,7 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data, for (i = 0; i < KEY_CONTENT_LEN/2; i ++) { hw = modulus[i*2] | (modulus[i*2+1]<<8); - if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + if (flash_program_halfword (addr, hw) != 0) return -1; addr += 2; } @@ -581,28 +477,13 @@ flash_cnt123_clear (const uint8_t **addr_p) } -static int -flash_check_blank (const uint8_t *page, int size) -{ - const uint8_t *p; - - for (p = page; p < page + size; p++) - if (*p != 0xff) - return 0; - - return 1; -} - - -#define FLASH_CH_CERTIFICATE_SIZE 2048 +#if defined(CERTDO_SUPPORT) int flash_erase_binary (uint8_t file_id) { - const uint8_t *p; - if (file_id == FILEID_CH_CERTIFICATE) { - p = &ch_certificate_start; + const uint8_t *p = &ch_certificate_start; if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0) { flash_erase_page ((uint32_t)p); @@ -613,9 +494,10 @@ flash_erase_binary (uint8_t file_id) return 0; } - else - return -1; + + return -1; } +#endif int @@ -625,16 +507,23 @@ flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t maxsize; const uint8_t *p; - if (file_id == FILEID_CH_CERTIFICATE) - { - maxsize = FLASH_CH_CERTIFICATE_SIZE; - p = &ch_certificate_start; - } - else if (file_id == FILEID_SERIAL_NO) + if (file_id == FILEID_SERIAL_NO) { maxsize = 6; p = &openpgpcard_aid[8]; } + else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3) + { + maxsize = KEY_CONTENT_LEN; + p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0); + } +#if defined(CERTDO_SUPPORT) + else if (file_id == FILEID_CH_CERTIFICATE) + { + maxsize = FLASH_CH_CERTIFICATE_SIZE; + p = &ch_certificate_start; + } +#endif else return -1; @@ -646,11 +535,14 @@ flash_write_binary (uint8_t file_id, const uint8_t *data, uint32_t addr; int i; + if (flash_check_blank (p + offset, len) == 0) + return -1; + addr = (uint32_t)p + offset; for (i = 0; i < len/2; i++) { hw = data[i*2] | (data[i*2+1]<<8); - if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) + if (flash_program_halfword (addr, hw) != 0) flash_warning ("DO WRITE ERROR"); addr += 2; } diff --git a/src/gnuk.h b/src/gnuk.h index 196e4ed..46a7418 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -1,3 +1,17 @@ +/* + * We declare some of libc functions here, because we will + * remove dependency on libc in future, possibly. + */ +extern size_t strlen (const char *s); +extern int strncmp(const char *s1, const char *s2, size_t n); +extern void *memcpy (void *dest, const void *src, size_t n); +extern void *memset (void *s, int c, size_t n); +extern int memcmp (const void *s1, const void *s2, size_t n); +extern void *memmove(void *dest, const void *src, size_t n); + +/* + * Debug functions + */ extern Thread *stdout_thread; #define EV_TX_READY ((eventmask_t)1) @@ -11,44 +25,49 @@ extern void put_binary (const char *s, int len); extern void _write (const char *, int); + /* - * We declare some of libc functions here, because we will - * remove dependency on libc in future. + * Application layer <-> CCID layer data structure */ -extern size_t strlen (const char *s); -extern int strncmp(const char *s1, const char *s2, size_t n); -extern void *memcpy (void *dest, const void *src, size_t n); -extern void *memset (void *s, int c, size_t n); -extern int memcmp (const void *s1, const void *s2, size_t n); -extern void *memmove(void *dest, const void *src, size_t n); +struct apdu { + uint8_t seq; + + /* command APDU */ + uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */ + uint8_t *cmd_apdu_data; + uint16_t cmd_apdu_data_len; /* Nc, calculated by Lc field */ + uint16_t expected_res_size; /* Ne, calculated by Le field */ + + /* response APDU */ + uint16_t sw; + uint8_t *res_apdu_data; + uint16_t res_apdu_data_len; +}; + +extern struct apdu apdu; #define EV_EXEC_FINISHED ((eventmask_t)2) /* GPG Execution finished */ -/* maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */ -#define MAX_CMD_APDU_SIZE (7+282) /* header + data */ -/* maximum res apdu data is public key 5+9+256+2 (gpg_do_public_key) */ -#define MAX_RES_APDU_SIZE ((5+9+256)+2) /* Data + status */ +/* GPG thread */ +#define EV_PINPAD_INPUT_DONE ((eventmask_t)1) +#define EV_NOP ((eventmask_t)2) +#define EV_CMD_AVAILABLE ((eventmask_t)4) +#define EV_VERIFY_CMD_AVAILABLE ((eventmask_t)8) +#define EV_MODIFY_CMD_AVAILABLE ((eventmask_t)16) + +/* Maximum cmd apdu data is key import 22+4+128+128 (proc_key_import) */ +#define MAX_CMD_APDU_DATA_SIZE (22+4+128+128) /* without header */ +/* Maximum res apdu data is public key 5+9+256 (gpg_do_public_key) */ +#define MAX_RES_APDU_DATA_SIZE (5+9+256) /* without trailer */ #define ICC_MSG_HEADER_SIZE 10 -#define cmd_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE]) -#define res_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE]) -extern int icc_data_size; -#define cmd_APDU_size icc_data_size -extern int res_APDU_size; -extern const uint8_t *res_APDU_pointer; +#define res_APDU apdu.res_apdu_data +#define res_APDU_size apdu.res_apdu_data_len /* USB buffer size of LL (Low-level): size of single Bulk transaction */ #define USB_LL_BUF_SIZE 64 -/* - * USB buffer size of USB-ICC driver - * (Changing this, dwMaxCCIDMessageLength too !!) - */ -#define USB_BUF_SIZE ((10 + 10 + MAX_CMD_APDU_SIZE + USB_LL_BUF_SIZE - 1) \ - / USB_LL_BUF_SIZE * USB_LL_BUF_SIZE) -extern uint8_t icc_buffer[USB_BUF_SIZE]; - enum icc_state { ICC_STATE_START, /* Initial */ @@ -57,9 +76,12 @@ enum icc_state ICC_STATE_EXECUTE, /* Busy4 */ ICC_STATE_RECEIVE, /* APDU Received Partially */ ICC_STATE_SEND, /* APDU Sent Partially */ + + ICC_STATE_EXITED, /* ICC Thread Terminated */ + ICC_STATE_EXEC_REQUESTED, /* Exec requested */ }; -extern volatile enum icc_state icc_state; +extern enum icc_state *icc_state_p; extern volatile uint8_t auth_status; #define AC_NONE_AUTHORIZED 0x00 @@ -72,6 +94,7 @@ extern volatile uint8_t auth_status; #define PW_ERR_PW1 0 #define PW_ERR_RC 1 #define PW_ERR_PW3 2 +extern int gpg_pw_get_retry_counter (int who); extern int gpg_pw_locked (uint8_t which); extern void gpg_pw_reset_err_counter (uint8_t which); extern void gpg_pw_increment_err_counter (uint8_t which); @@ -79,8 +102,8 @@ extern void gpg_pw_increment_err_counter (uint8_t which); extern int ac_check_status (uint8_t ac_flag); extern int verify_pso_cds (const uint8_t *pw, int pw_len); extern int verify_other (const uint8_t *pw, int pw_len); -extern int verify_user_0 (const uint8_t *pw, int buf_len, int pw_len_known, - const uint8_t *ks_pw1); +extern int verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, + int pw_len_known, const uint8_t *ks_pw1); extern int verify_admin (const uint8_t *pw, int pw_len); extern int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known); @@ -90,7 +113,7 @@ extern void ac_reset_admin (void); extern void ac_fini (void); -extern void set_res_apdu (uint8_t sw1, uint8_t sw2); +extern void set_res_sw (uint8_t sw1, uint8_t sw2); extern uint16_t data_objects_number_of_bytes; extern void gpg_data_scan (const uint8_t *p); @@ -98,7 +121,9 @@ extern void gpg_data_copy (const uint8_t *p); extern void gpg_do_get_data (uint16_t tag, int with_tag); extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len); extern void gpg_do_public_key (uint8_t kk_byte); +extern void gpg_do_keygen (uint8_t kk_byte); +extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno); enum kind_of_key { @@ -107,30 +132,36 @@ enum kind_of_key { GPG_KEY_FOR_AUTHENTICATION, }; -extern void flash_unlock (void); extern const uint8_t *flash_init (void); extern void flash_do_release (const uint8_t *); extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len); extern uint8_t *flash_key_alloc (void); +extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, + const uint8_t *modulus); extern void flash_keystore_release (void); extern void flash_set_data_pool_last (const uint8_t *p); extern void flash_clear_halfword (uint32_t addr); extern void flash_increment_counter (uint8_t counter_tag_nr); extern void flash_reset_counter (uint8_t counter_tag_nr); -#define FILEID_CH_CERTIFICATE 0 -#define FILEID_RANDOM 1 -#define FILEID_SERIAL_NO 2 +#define FILEID_SERIAL_NO 0 +#define FILEID_UPDATE_KEY_0 1 +#define FILEID_UPDATE_KEY_1 2 +#define FILEID_UPDATE_KEY_2 3 +#define FILEID_UPDATE_KEY_3 4 +#define FILEID_CH_CERTIFICATE 5 extern int flash_erase_binary (uint8_t file_id); extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset); +#define FLASH_CH_CERTIFICATE_SIZE 2048 + /* Linker set these two symbols */ extern uint8_t ch_certificate_start; extern uint8_t random_bits_start; -#define KEY_MAGIC_LEN 8 #define KEY_CONTENT_LEN 256 /* p and q */ -#define GNUK_MAGIC "Gnuk KEY" +#define INITIAL_VECTOR_SIZE 16 +#define DATA_ENCRYPTION_KEY_SIZE 16 /* encrypted data content */ struct key_data { @@ -139,22 +170,21 @@ struct key_data { struct key_data_internal { uint8_t data[KEY_CONTENT_LEN]; /* p and q */ - uint32_t check; - uint32_t random; - char magic[KEY_MAGIC_LEN]; + uint8_t checksum[DATA_ENCRYPTION_KEY_SIZE]; }; -#define ADDITIONAL_DATA_SIZE 16 -#define DATA_ENCRYPTION_KEY_SIZE 16 struct prvkey_data { const uint8_t *key_addr; /* - * CRM: [C]heck, [R]andom, and [M]agic in struct key_data_internal - * + * IV: Initial Vector */ - uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE]; + uint8_t iv[INITIAL_VECTOR_SIZE]; /* - * DEK: Data Encryption Key + * Checksum + */ + uint8_t checksum_encrypted[DATA_ENCRYPTION_KEY_SIZE]; + /* + * DEK (Data Encryption Key) encrypted */ uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */ uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */ @@ -165,12 +195,14 @@ struct prvkey_data { #define BY_RESETCODE 2 #define BY_ADMIN 3 -extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus); +extern void s2k (int who, const unsigned char *input, unsigned int ilen, + unsigned char output[32]); + #define KEYSTRING_PASSLEN_SIZE 1 #define KEYSTRING_SALT_SIZE 8 /* optional */ #define KEYSTRING_ITER_SIZE 1 /* optional */ -#define KEYSTRING_MD_SIZE 20 +#define KEYSTRING_MD_SIZE 32 #define KEYSTRING_SIZE_PW1 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE) #define KEYSTRING_SIZE_RC (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE) #define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \ @@ -205,6 +237,9 @@ extern int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *); extern const uint8_t *modulus_calc (const uint8_t *, int); extern void modulus_free (const uint8_t *); extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *); +extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash, + const uint8_t *signature); +extern const uint8_t *rsa_genkey (void); extern const uint8_t *gpg_do_read_simple (uint8_t); extern void gpg_do_write_simple (uint8_t, const uint8_t *, int); @@ -272,7 +307,7 @@ extern uint8_t admin_authorized; /* * Representation of Boolean object: * 0: No record in flash memory - * 1: 0xc?00 + * 1: 0xf000 */ #define NR_BOOL_PW1_LIFETIME 0xf0 /* @@ -281,7 +316,7 @@ extern uint8_t admin_authorized; /* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */ /* * Representation of 123-counters: - * 0: No record in flash memory + * 0: No record in flash memory * 1: 0xfe?? 0xffff * 2: 0xfe?? 0xc3c3 * 3: 0xfe?? 0x0000 @@ -298,11 +333,11 @@ extern const uint8_t *random_bytes_get (void); extern void random_bytes_free (const uint8_t *); /* 4-byte salt */ extern uint32_t get_salt (void); +/* iterator returning a byta at a time */ +extern uint8_t random_byte (void *arg); extern uint32_t hardclock (void); -extern void set_led (int); - #define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */ extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1]; @@ -330,17 +365,31 @@ extern void flash_bool_write_internal (const uint8_t *p, int nr); extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v); extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len); -extern const unsigned char *unique_device_id (void); extern const uint8_t gnukStringSerial[]; +#define LED_ONESHOT ((eventmask_t)1) +#define LED_TWOSHOTS ((eventmask_t)2) +#define LED_SHOW_STATUS ((eventmask_t)4) +#define LED_START_COMMAND ((eventmask_t)8) +#define LED_FINISH_COMMAND ((eventmask_t)16) +#define LED_FATAL ((eventmask_t)32) +extern void led_blink (int spec); + #if defined(PINPAD_SUPPORT) -#if defined(PINPAD_CIR_SUPPORT) +# if defined(PINPAD_CIR_SUPPORT) extern void cir_ext_disable (void); extern void cir_ext_enable (void); -#elif defined(PINPAD_DIAL_SUPPORT) +# elif defined(PINPAD_DIAL_SUPPORT) extern void dial_sw_disable (void); extern void dial_sw_enable (void); -#endif +# elif defined(PINPAD_DND_SUPPORT) +extern uint8_t media_available; +extern void msc_init (void); +extern void msc_media_insert_change (int available); +extern int msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size); +extern int msc_scsi_read (uint32_t lba, const uint8_t **sector_p); +extern void msc_scsi_stop (uint8_t code); +# endif #define PIN_INPUT_CURRENT 1 #define PIN_INPUT_NEW 2 #define PIN_INPUT_CONFIRM 3 @@ -348,5 +397,8 @@ extern void dial_sw_enable (void); extern uint8_t pin_input_buffer[MAX_PIN_CHARS]; extern uint8_t pin_input_len; -extern msg_t pin_main (void *arg); +extern int pinpad_getline (int msg_code, systime_t timeout); + #endif + +extern uint8_t _regnual_start, __heap_end__; diff --git a/src/gnuk.ld.in b/src/gnuk.ld.in index cefb008..1ab53e7 100644 --- a/src/gnuk.ld.in +++ b/src/gnuk.ld.in @@ -27,16 +27,21 @@ /* * ST32F103 memory setup. */ -__main_stack_size__ = 0x0200; +__main_stack_size__ = 0x0400; __process_stack_size__ = 0x0200; __stacks_total_size__ = __main_stack_size__ + __process_stack_size__; MEMORY { - flash : org = @ORIGIN@, len = @FLASH_SIZE@k + flash0 : org = @ORIGIN@, len = 4k + flash : org = @ORIGIN@+0x1000, len = @FLASH_SIZE@k - 4k ram : org = 0x20000000, len = 20k } +/* __flash_start__: flash ROM start address regardless of DFU_SUPPORT */ +__flash_start__ = 0x08001000; +__flash_end__ = ORIGIN(flash) + LENGTH(flash); + __ram_start__ = ORIGIN(ram); __ram_size__ = LENGTH(ram); __ram_end__ = __ram_start__ + __ram_size__; @@ -45,6 +50,22 @@ SECTIONS { . = 0; + .sys : ALIGN(16) SUBALIGN(16) + { + _sys = .; + KEEP(*(.vectors)) + . = ALIGN(16); + *(.sys.version) + sys.o(.text) + sys.o(.text.*) + sys.o(.rodata) + sys.o(.rodata.*) + . = ALIGN(1024); + *(.sys.0) + *(.sys.1) + *(.sys.2) + } > flash0 + .text : ALIGN(16) SUBALIGN(16) { _text = .; @@ -114,7 +135,10 @@ SECTIONS PROVIDE(end = .); _end = .; + . = ALIGN(512); + _regnual_start = .; +@CERTDO_SUPPORT_START@ .gnuk_ch_certificate : { . = ALIGN (@FLASH_PAGE_SIZE@); @@ -123,9 +147,11 @@ SECTIONS . += 1920; . = ALIGN (@FLASH_PAGE_SIZE@); } > flash =0xffffffff +@CERTDO_SUPPORT_END@ .gnuk_flash : { + . = ALIGN (@FLASH_PAGE_SIZE@); _data_pool = .; KEEP(*(.gnuk_data)) . = ALIGN(@FLASH_PAGE_SIZE@); @@ -133,6 +159,9 @@ SECTIONS _keystore_pool = .; . += 512*3; . = ALIGN(@FLASH_PAGE_SIZE@); + _updatekey_store = .; + . += 1024; + . = ALIGN(@FLASH_PAGE_SIZE@); } > flash =0xffffffff } diff --git a/src/hardclock.c b/src/hardclock.c deleted file mode 100644 index 30cc8c1..0000000 --- a/src/hardclock.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "config.h" -#include "ch.h" -#include "hal.h" -#include "gnuk.h" - -uint32_t -hardclock (void) -{ - uint32_t r = SysTick->VAL; - - DEBUG_INFO ("Random: "); - DEBUG_WORD (r); - return r; -} diff --git a/src/main.c b/src/main.c index 9344ee2..701af2b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ /* * main.c - main routine of Gnuk * - * Copyright (C) 2010 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -22,16 +22,12 @@ */ #include "config.h" - -#include "usb_lib.h" - #include "ch.h" +#include "hal.h" +#include "sys.h" #include "gnuk.h" #include "usb_lld.h" -#include "usb_istr.h" -#include "usb_desc.h" -#include "hw_config.h" -#include "usb_pwr.h" +#include "usb-cdc.h" #ifdef DEBUG struct stdout { @@ -106,10 +102,14 @@ STDOUTthread (void *arg) p = stdout.str; len = stdout.size; - while (len > 0) + while (1) { int i; + if (len == 0) + if (count_in != VIRTUAL_COM_PORT_DATA_SIZE) + break; + if (len < VIRTUAL_COM_PORT_DATA_SIZE) { for (i = 0; i < len; i++) @@ -128,8 +128,7 @@ STDOUTthread (void *arg) chEvtClear (EV_TX_READY); - USB_SIL_Write (EP3_IN, buffer_in, count_in); - SetEPTxValid (ENDP3); + usb_lld_write (ENDP3, buffer_in, count_in); chEvtWaitOne (EV_TX_READY); } @@ -143,6 +142,19 @@ STDOUTthread (void *arg) goto again; return 0; } + +void +EP3_IN_Callback (void) +{ + if (stdout_thread) + chEvtSignalI (stdout_thread, EV_TX_READY); +} + +void +EP5_OUT_Callback (void) +{ + usb_lld_rx_enable (ENDP5); +} #else void _write (const char *s, int size) @@ -158,13 +170,15 @@ extern msg_t USBthread (void *arg); /* * main thread does 1-bit LED display output */ -#define LED_TIMEOUT_INTERVAL MS2ST(100) -#define LED_TIMEOUT_ZERO MS2ST(50) -#define LED_TIMEOUT_ONE MS2ST(200) -#define LED_TIMEOUT_STOP MS2ST(500) +#define MAIN_TIMEOUT_INTERVAL MS2ST(5000) + +#define LED_TIMEOUT_INTERVAL MS2ST(75) +#define LED_TIMEOUT_ZERO MS2ST(25) +#define LED_TIMEOUT_ONE MS2ST(100) +#define LED_TIMEOUT_STOP MS2ST(200) -#define ID_OFFSET 12 +#define ID_OFFSET 24 static void device_initialize_once (void) { @@ -182,7 +196,7 @@ device_initialize_once (void) for (i = 0; i < 4; i++) { uint8_t b = u[i]; - uint8_t nibble; + uint8_t nibble; nibble = (b >> 4); nibble += (nibble >= 10 ? ('A' - 10) : '0'); @@ -196,6 +210,115 @@ device_initialize_once (void) static volatile uint8_t fatal_code; +static Thread *main_thread; + +static void display_fatal_code (void) +{ + while (1) + { + set_led (1); + chThdSleep (LED_TIMEOUT_ZERO); + set_led (0); + chThdSleep (LED_TIMEOUT_INTERVAL); + set_led (1); + chThdSleep (LED_TIMEOUT_ZERO); + set_led (0); + chThdSleep (LED_TIMEOUT_INTERVAL); + set_led (1); + chThdSleep (LED_TIMEOUT_ZERO); + set_led (0); + chThdSleep (LED_TIMEOUT_STOP); + set_led (1); + if (fatal_code & 1) + chThdSleep (LED_TIMEOUT_ONE); + else + chThdSleep (LED_TIMEOUT_ZERO); + set_led (0); + chThdSleep (LED_TIMEOUT_INTERVAL); + set_led (1); + if (fatal_code & 2) + chThdSleep (LED_TIMEOUT_ONE); + else + chThdSleep (LED_TIMEOUT_ZERO); + set_led (0); + chThdSleep (LED_TIMEOUT_INTERVAL); + set_led (1); + chThdSleep (LED_TIMEOUT_STOP); + set_led (0); + chThdSleep (LED_TIMEOUT_INTERVAL*10); + } +} + +static uint8_t led_inverted; + +static eventmask_t emit_led (int on_time, int off_time) +{ + eventmask_t m; + + set_led (!led_inverted); + m = chEvtWaitOneTimeout (ALL_EVENTS, on_time); + set_led (led_inverted); + if (m) return m; + if ((m = chEvtWaitOneTimeout (ALL_EVENTS, off_time))) + return m; + return 0; +} + +static eventmask_t display_status_code (void) +{ + enum icc_state icc_state; + eventmask_t m; + + if (icc_state_p == NULL) + icc_state = ICC_STATE_START; + else + icc_state = *icc_state_p; + + if (icc_state == ICC_STATE_START) + return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP); + else + /* GPGthread running */ + { + if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)? + LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, + LED_TIMEOUT_INTERVAL))) + return m; + if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)? + LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, + LED_TIMEOUT_INTERVAL))) + return m; + if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)? + LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, + LED_TIMEOUT_INTERVAL))) + return m; + + if (icc_state == ICC_STATE_WAIT) + { + if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP * 2))) + return m; + } + else + { + if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL))) + return m; + + if ((m = emit_led (icc_state == ICC_STATE_RECEIVE? + LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO, + LED_TIMEOUT_STOP))) + return m; + } + + return 0; + } +} + +void +led_blink (int spec) +{ + chEvtSignal (main_thread, spec); +} + + /* * Entry point. * @@ -203,19 +326,28 @@ static volatile uint8_t fatal_code; * See the hwinit1_common function. */ int -main (int argc, char **argv) +main (int argc, char *argv[]) { - int count = 0; + unsigned int count = 0; (void)argc; (void)argv; + main_thread = chThdSelf (); + flash_unlock (); device_initialize_once (); - usb_lld_init (); - USB_Init (); + usb_lld_init (Config_Descriptor.Descriptor[7]); random_init (); + while (1) + { + if (bDeviceState != UNCONNECTED) + break; + + chThdSleepMilliseconds (250); + } + #ifdef DEBUG stdout_init (); @@ -229,107 +361,53 @@ main (int argc, char **argv) chThdCreateStatic (waUSBthread, sizeof(waUSBthread), NORMALPRIO, USBthread, NULL); +#ifdef PINPAD_DND_SUPPORT + msc_init (); +#endif + + while (1) { + eventmask_t m; + + if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED) + break; + + m = chEvtWaitOneTimeout (ALL_EVENTS, MAIN_TIMEOUT_INTERVAL); + got_it: count++; - - if (fatal_code != 0) + switch (m) { + case LED_ONESHOT: + if ((m = emit_led (MS2ST (100), MAIN_TIMEOUT_INTERVAL))) goto got_it; + break; + case LED_TWOSHOTS: + if ((m = emit_led (MS2ST (50), MS2ST (50)))) goto got_it; + if ((m = emit_led (MS2ST (50), MAIN_TIMEOUT_INTERVAL))) goto got_it; + break; + case LED_SHOW_STATUS: + if ((count & 0x07) != 0) continue; /* Display once for eight times */ + if ((m = display_status_code ())) goto got_it; + break; + case LED_START_COMMAND: set_led (1); - chThdSleep (LED_TIMEOUT_ZERO); + led_inverted = 1; + break; + case LED_FINISH_COMMAND: + m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP); + led_inverted = 0; set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_STOP); - set_led (1); - if (fatal_code & 1) - chThdSleep (LED_TIMEOUT_ONE); - else - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - if (fatal_code & 2) - chThdSleep (LED_TIMEOUT_ONE); - else - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - chThdSleep (LED_TIMEOUT_STOP); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - } - - if (bDeviceState != CONFIGURED) - { - set_led (1); - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_STOP * 3); + if (m) + goto got_it; + break; + case LED_FATAL: + display_fatal_code (); + break; + default: + if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP))) + goto got_it; + break; } - else - /* Device configured */ - if (icc_state == ICC_STATE_START) - { - set_led (1); - chThdSleep (LED_TIMEOUT_ONE); - set_led (0); - chThdSleep (LED_TIMEOUT_STOP * 3); - } - else - /* GPGthread running */ - { - set_led (1); - if ((auth_status & AC_ADMIN_AUTHORIZED) != 0) - chThdSleep (LED_TIMEOUT_ONE); - else - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - if ((auth_status & AC_OTHER_AUTHORIZED) != 0) - chThdSleep (LED_TIMEOUT_ONE); - else - chThdSleep (LED_TIMEOUT_ZERO); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0) - chThdSleep (LED_TIMEOUT_ONE); - else - chThdSleep (LED_TIMEOUT_ZERO); - - if (icc_state == ICC_STATE_WAIT) - { - set_led (0); - chThdSleep (LED_TIMEOUT_STOP * 2); - } - else if (icc_state == ICC_STATE_RECEIVE) - { - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - chThdSleep (LED_TIMEOUT_ONE); - set_led (0); - chThdSleep (LED_TIMEOUT_STOP); - } - else - { - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - set_led (1); - chThdSleep (LED_TIMEOUT_STOP); - set_led (0); - chThdSleep (LED_TIMEOUT_INTERVAL); - } - } #ifdef DEBUG_MORE if (bDeviceState == CONFIGURED && (count % 10) == 0) @@ -342,6 +420,41 @@ main (int argc, char **argv) #endif } + set_led (1); + usb_lld_shutdown (); + /* Disable SysTick */ + SysTick->CTRL = 0; + /* Disable all interrupts */ + port_disable (); + /* Set vector */ + SCB->VTOR = (uint32_t)&_regnual_start; +#ifdef DFU_SUPPORT +#define FLASH_SYS_START_ADDR 0x08000000 +#define FLASH_SYS_END_ADDR (0x08000000+0x1000) + { + extern uint8_t _sys; + uint32_t addr; + handler *new_vector = (handler *)FLASH_SYS_START_ADDR; + void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10]; + + /* Kill DFU */ + for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR; + addr += FLASH_PAGE_SIZE) + flash_erase_page (addr); + + /* copy system service routines */ + flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000); + + /* Leave Gnuk to exec reGNUal */ + (*func) (*((void (**)(void))(&_regnual_start+4))); + for (;;); + } +#else + /* Leave Gnuk to exec reGNUal */ + flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4))); +#endif + + /* Never reached */ return 0; } @@ -349,6 +462,7 @@ void fatal (uint8_t code) { fatal_code = code; + chEvtSignal (main_thread, LED_FATAL); _write ("fatal\r\n", 7); for (;;); } diff --git a/src/neug.c b/src/neug.c index be95ae9..5753094 100644 --- a/src/neug.c +++ b/src/neug.c @@ -32,15 +32,15 @@ static Thread *rng_thread; /* Total number of channels to be sampled by a single ADC operation.*/ #define ADC_GRP1_NUM_CHANNELS 2 - + /* Depth of the conversion buffer, channels are sampled one time each.*/ #define ADC_GRP1_BUF_DEPTH 4 - + /* * ADC samples buffer. */ static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH]; - + static void adccb (adcsample_t *buffer, size_t n); /* diff --git a/src/openpgp-do.c b/src/openpgp-do.c index aa36a7b..759069e 100644 --- a/src/openpgp-do.c +++ b/src/openpgp-do.c @@ -1,7 +1,7 @@ /* * openpgp-do.c -- OpenPGP card Data Objects (DO) handling * - * Copyright (C) 2010, 2011 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -25,12 +25,12 @@ #include "config.h" #include "ch.h" +#include "sys.h" #include "gnuk.h" #include "openpgp.h" #include "polarssl/config.h" #include "polarssl/aes.h" -#include "polarssl/sha1.h" #define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */ static const uint8_t *pw_err_counter_p[3]; @@ -41,6 +41,17 @@ gpg_pw_get_err_counter (uint8_t which) return flash_cnt123_get_value (pw_err_counter_p[which]); } +int +gpg_pw_get_retry_counter (int who) +{ + if (who == 0x81 || who == 0x82) + return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW1); + else if (who == 0x83) + return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_PW3); + else + return PASSWORD_ERRORS_MAX - gpg_pw_get_err_counter (PW_ERR_RC); +} + int gpg_pw_locked (uint8_t which) { @@ -77,12 +88,11 @@ uint16_t data_objects_number_of_bytes; static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = { 10, 0x00, - 0x31, 0x80, /* Full DF name */ + 0x31, 0x84, /* Full DF name, GET DATA, MF */ 0x73, - 0x80, 0x01, 0x40, /* Full DF name */ + 0x80, 0x01, 0x80, /* Full DF name */ /* 1-byte */ - /* No command chaining */ - /* Extended Lc and Le */ + /* Command chaining, No extended Lc and Le */ 0x00, 0x90, 0x00 /* Status info (no life cycle management) */ }; @@ -90,23 +100,24 @@ static const uint8_t historical_bytes[] __attribute__ ((aligned (1))) = { static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = { 10, 0x30, /* - * No SM, No get challenge, + * No SM, + * No get challenge, * Key import supported, * PW status byte can be put, * No private_use_DO, * No algo change allowed */ 0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */ - 0x00, 0x00, /* Max get challenge */ - 0x07, 0xfe, /* max. length of cardholder certificate (2KB - 2)*/ - /* Max. length of command data */ - (MAX_CMD_APDU_SIZE>>8), (MAX_CMD_APDU_SIZE&0xff), - /* Max. length of response data */ -#if 0 - (MAX_RES_APDU_SIZE>>8), (MAX_RES_APDU_SIZE&0xff), + 0x00, 0x00, /* Max get challenge (0: Get challenge not supported) */ +#ifdef CERTDO_SUPPORT + 0x08, 0x00, /* max. length of cardholder certificate (2KiB) */ #else - 0x08, 0x00, /* the case of cardholder ceritificate */ + 0x00, 0x00, #endif + /* Max. length of command APDU data */ + 0x00, 0xff, + /* Max. length of response APDU data */ + 0x01, 0x00, }; /* Algorithm Attributes */ @@ -162,6 +173,17 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc) } } +static void +gpg_reset_digital_signature_counter (void) +{ + if (digital_signature_counter != 0) + { + flash_put_data (NR_COUNTER_DS); + flash_put_data (NR_COUNTER_DS_LSB); + digital_signature_counter = 0; + } +} + void gpg_increment_digital_signature_counter (void) { @@ -413,10 +435,12 @@ do_kgtime_all (uint16_t tag, int with_tag) } const uint8_t openpgpcard_aid[] = { - 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01, - 0x02, 0x00, /* Version 2.0 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */ + 0xd2, 0x76, /* D: National, 276: DEU ISO 3166-1 */ + 0x00, 0x01, 0x24, /* Registered Application Provider Identifier */ + 0x01, /* Application: OpenPGPcard */ + 0x02, 0x00, /* Version 2.0 */ /* v. id */ /* serial number */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */ }; static int @@ -529,7 +553,7 @@ proc_resetting_code (const uint8_t *data, int len) newpw_len = len; newpw = data; - sha1 (newpw, newpw_len, new_ks); + s2k (BY_RESETCODE, newpw, newpw_len, new_ks); new_ks0[0] = newpw_len; r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks); if (r <= -2) @@ -558,40 +582,58 @@ proc_resetting_code (const uint8_t *data, int len) } static void -encrypt (const uint8_t *key_str, uint8_t *data, int len) +encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) { aes_context aes; - uint8_t iv[16]; + uint8_t iv0[INITIAL_VECTOR_SIZE]; int iv_offset; DEBUG_INFO ("ENC\r\n"); DEBUG_BINARY (data, len); - aes_setkey_enc (&aes, key_str, 128); - memset (iv, 0, 16); + aes_setkey_enc (&aes, key, 128); + memcpy (iv0, iv, INITIAL_VECTOR_SIZE); iv_offset = 0; - aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data); + aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data); } /* Signing, Decryption, and Authentication */ struct key_data kd[3]; static void -decrypt (const uint8_t *key_str, uint8_t *data, int len) +decrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) { aes_context aes; - uint8_t iv[16]; + uint8_t iv0[INITIAL_VECTOR_SIZE]; int iv_offset; - aes_setkey_enc (&aes, key_str, 128); - memset (iv, 0, 16); + aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */ + memcpy (iv0, iv, INITIAL_VECTOR_SIZE); iv_offset = 0; - aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data); + aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv0, data, data); DEBUG_INFO ("DEC\r\n"); DEBUG_BINARY (data, len); } +static void +encrypt_dek (const uint8_t *key_string, uint8_t *dek) +{ + aes_context aes; + + aes_setkey_enc (&aes, key_string, 128); + aes_crypt_ecb (&aes, AES_ENCRYPT, dek, dek); +} + +static void +decrypt_dek (const uint8_t *key_string, uint8_t *dek) +{ + aes_context aes; + + aes_setkey_dec (&aes, key_string, 128); + aes_crypt_ecb (&aes, AES_DECRYPT, dek, dek); +} + static uint8_t get_do_ptr_nr_for_kk (enum kind_of_key kk) { @@ -613,6 +655,25 @@ gpg_do_clear_prvkey (enum kind_of_key kk) memset ((void *)&kd[kk], 0, sizeof (struct key_data)); } + +static int +compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc) +{ + unsigned int i; + uint32_t d[4] = { 0, 0, 0, 0 }; + + for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++) + d[i&3] ^= *(uint32_t *)(&kdi->data[i*4]); + + if (check_or_calc == 0) /* store */ + { + memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE); + return 0; + } + else /* check */ + return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0; +} + /* * Return 1 on success, * 0 if none, @@ -623,66 +684,58 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring) { uint8_t nr = get_do_ptr_nr_for_kk (kk); const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; - uint8_t *key_addr; + const uint8_t *key_addr; uint8_t dek[DATA_ENCRYPTION_KEY_SIZE]; + const uint8_t *iv; struct key_data_internal kdi; + DEBUG_INFO ("Loading private key: "); + DEBUG_BYTE (kk); + if (do_data == NULL) return 0; - key_addr = *(uint8_t **)&(do_data)[1]; + key_addr = *(const uint8_t **)&(do_data)[1]; /* Possible unaligned access */ memcpy (kdi.data, key_addr, KEY_CONTENT_LEN); - memcpy (((uint8_t *)&kdi.check), do_data+5, ADDITIONAL_DATA_SIZE); + iv = do_data+5; + memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE); - memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE); - decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE); + memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE); + decrypt_dek (keystring, dek); - decrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal)); - if (memcmp (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0) + decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal)); + memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE); + if (!compute_key_data_checksum (&kdi, 1)) { DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n"); return -1; } - /* more sanity check??? */ memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN); + DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN); return 1; } -static uint32_t -calc_check32 (const uint8_t *p, int len) -{ - uint32_t check = 0; - uint32_t *data = (uint32_t *)p; - int i; - - for (i = 0; i < len/4; i++) - check += data[i]; - - return check; -} static int8_t num_prv_keys; static int gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, - const uint8_t *keystring_admin) + const uint8_t *keystring_admin, const uint8_t *modulus) { uint8_t nr = get_do_ptr_nr_for_kk (kk); const uint8_t *p; int r; - const uint8_t *modulus; struct prvkey_data *pd; uint8_t *key_addr; - const uint8_t *dek; + const uint8_t *dek, *iv; const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; const uint8_t *ks_pw1; const uint8_t *ks_rc; struct key_data_internal kdi; - -#if 0 - assert (key_len == KEY_CONTENT_LEN); -#endif + int modulus_allocated_here = 0; + uint8_t ks_pw1_len = 0; + uint8_t ks_rc_len = 0; DEBUG_INFO ("Key import\r\n"); DEBUG_SHORT (key_len); @@ -691,15 +744,23 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, /* No replace support, you need to remove it first. */ return -1; + if (key_len != KEY_CONTENT_LEN) + return -1; + pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data)); if (pd == NULL) return -1; - modulus = modulus_calc (key_data, key_len); if (modulus == NULL) { - free (pd); - return -1; + modulus = modulus_calc (key_data, key_len); + if (modulus == NULL) + { + free (pd); + return -1; + } + + modulus_allocated_here = 1; } DEBUG_INFO ("Getting keystore address...\r\n"); @@ -707,7 +768,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, if (key_addr == NULL) { free (pd); - modulus_free (modulus); + if (modulus_allocated_here) + modulus_free (modulus); return -1; } @@ -715,21 +777,21 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, DEBUG_WORD ((uint32_t)key_addr); memcpy (kdi.data, key_data, KEY_CONTENT_LEN); - kdi.check = calc_check32 (key_data, KEY_CONTENT_LEN); - kdi.random = get_salt (); - memcpy (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN); + compute_key_data_checksum (&kdi, 0); - dek = random_bytes_get (); /* 16-byte random bytes */ + dek = random_bytes_get (); /* 32-byte random bytes */ + iv = dek + DATA_ENCRYPTION_KEY_SIZE; memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE); memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE); memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE); ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); - encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal)); + encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal)); r = flash_key_write (key_addr, kdi.data, modulus); - modulus_free (modulus); + if (modulus_allocated_here) + modulus_free (modulus); if (r < 0) { @@ -739,32 +801,33 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, } pd->key_addr = key_addr; - memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE); - - if (kk == GPG_KEY_FOR_SIGNING) - ac_reset_pso_cds (); - else - ac_reset_other (); + memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE); + memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE); if (ks_pw1) - encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE); + { + ks_pw1_len = ks_pw1[0]; + encrypt_dek (ks_pw1+1, pd->dek_encrypted_1); + } else { - uint8_t ks123_pw1[KEYSTRING_SIZE_PW1]; + uint8_t ks[KEYSTRING_MD_SIZE]; - ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1); - sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1, - strlen (OPENPGP_CARD_INITIAL_PW1), ks123_pw1+1); - encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE); + s2k (BY_USER, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1, + strlen (OPENPGP_CARD_INITIAL_PW1), ks); + encrypt_dek (ks, pd->dek_encrypted_1); } if (ks_rc) - encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE); + { + ks_rc_len = ks_rc[0]; + encrypt_dek (ks_rc+1, pd->dek_encrypted_2); + } else memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE); if (keystring_admin) - encrypt (keystring_admin, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE); + encrypt_dek (keystring_admin, pd->dek_encrypted_3); else memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE); @@ -779,17 +842,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, if (++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered. */ { /* Remove contents of keystrings from DO, but length */ - if (ks_pw1) - { - uint8_t ks_pw1_len = ks_pw1[0]; - gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1); - } + if (ks_pw1_len) + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1); - if (ks_rc) - { - uint8_t ks_rc_len = ks_rc[0]; - gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1); - } + if (ks_rc_len) + gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1); } return 0; @@ -814,19 +871,21 @@ gpg_do_chks_prvkey (enum kind_of_key kk, if (pd == NULL) return -1; - memcpy (pd, &(do_data)[1], sizeof (struct prvkey_data)); - dek_p = ((uint8_t *)pd) + 4 + ADDITIONAL_DATA_SIZE - + DATA_ENCRYPTION_KEY_SIZE * (who_old - 1); + memcpy (pd, &do_data[1], sizeof (struct prvkey_data)); + flash_do_release (do_data); + + dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE + + DATA_ENCRYPTION_KEY_SIZE * who_old; memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE); - decrypt (old_ks, dek, DATA_ENCRYPTION_KEY_SIZE); - encrypt (new_ks, dek, DATA_ENCRYPTION_KEY_SIZE); + decrypt_dek (old_ks, dek); + encrypt_dek (new_ks, dek); dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old); memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE); + do_ptr[nr - NR_DO__FIRST__] = NULL; p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); do_ptr[nr - NR_DO__FIRST__] = p; - flash_do_release (do_data); free (pd); if (p == NULL) return -1; @@ -835,13 +894,13 @@ gpg_do_chks_prvkey (enum kind_of_key kk, } /* - * 4d, xx, xx: Extended Header List + * 4d, xx, xx, xx: Extended Header List * b6 00 (SIG) / b8 00 (DEC) / a4 00 (AUT) * 7f48, xx: cardholder private key template * 91 xx - * 92 xx - * 93 xx - * 5f48, xx: cardholder private key + * 92 xx xx + * 93 xx xx + * 5f48, xx xx xx: cardholder private key */ static int proc_key_import (const uint8_t *data, int len) @@ -849,6 +908,7 @@ proc_key_import (const uint8_t *data, int len) int r; enum kind_of_key kk; const uint8_t *keystring_admin; + const uint8_t *p = data; if (admin_authorized == BY_ADMIN) keystring_admin = keystring_md_pw3; @@ -857,12 +917,31 @@ proc_key_import (const uint8_t *data, int len) DEBUG_BINARY (data, len); - if (data[4] == 0xb6) - kk = GPG_KEY_FOR_SIGNING; - else if (data[4] == 0xb8) - kk = GPG_KEY_FOR_DECRYPTION; - else /* 0xa4 */ - kk = GPG_KEY_FOR_AUTHENTICATION; + if (*p++ != 0x4d) + return 0; + + /* length field */ + if (*p == 0x82) + p += 3; + else if (*p == 0x81) + p += 2; + else + p += 1; + + if (*p == 0xb6) + { + kk = GPG_KEY_FOR_SIGNING; + ac_reset_pso_cds (); + gpg_reset_digital_signature_counter (); + } + else + { + if (*p == 0xb8) + kk = GPG_KEY_FOR_DECRYPTION; + else /* 0xa4 */ + kk = GPG_KEY_FOR_AUTHENTICATION; + ac_reset_other (); + } if (len <= 22) { /* Deletion of the key */ @@ -882,6 +961,11 @@ proc_key_import (const uint8_t *data, int len) /* Delete PW1 and RC if any */ gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0); gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0); + + ac_reset_pso_cds (); + ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); } return 1; @@ -889,7 +973,7 @@ proc_key_import (const uint8_t *data, int len) /* It should starts with 00 01 00 01 (E) */ /* Skip E, 4-byte */ - r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin); + r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL); if (r < 0) return 0; else @@ -970,7 +1054,7 @@ gpg_do_table[] = { / sizeof (struct do_table_entry)) /* - * Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc. + * Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc. */ void gpg_data_scan (const uint8_t *p_start) @@ -1020,18 +1104,18 @@ gpg_data_scan (const uint8_t *p_start) } else switch (nr) - { - case NR_BOOL_PW1_LIFETIME: - pw1_lifetime_p = p - 1; - p++; - continue; - case NR_COUNTER_123: - p++; - if (second_byte <= PW_ERR_PW3) - pw_err_counter_p[second_byte] = p; - p += 2; - break; - } + { + case NR_BOOL_PW1_LIFETIME: + pw1_lifetime_p = p - 1; + p++; + continue; + case NR_COUNTER_123: + p++; + if (second_byte <= PW_ERR_PW3) + pw_err_counter_p[second_byte] = p; + p += 2; + break; + } } } @@ -1218,8 +1302,8 @@ copy_do (const struct do_table_entry *do_p, int with_tag) } case DO_PROC_READWRITE: { - int (*rw_func)(uint16_t, int, uint8_t *, int, int) - = (int (*)(uint16_t, int, uint8_t *, int, int))do_p->obj; + int (*rw_func)(uint16_t, int, const uint8_t *, int, int) + = (int (*)(uint16_t, int, const uint8_t *, int, int))do_p->obj; return rw_func (do_p->tag, with_tag, NULL, 0, 0); } @@ -1237,20 +1321,22 @@ copy_do (const struct do_table_entry *do_p, int with_tag) void gpg_do_get_data (uint16_t tag, int with_tag) { +#if defined(CERTDO_SUPPORT) if (tag == GPG_DO_CH_CERTIFICATE) { - res_APDU_pointer = &ch_certificate_start; - res_APDU_size = ((res_APDU_pointer[2] << 8) | res_APDU_pointer[3]); - if (res_APDU_size == 0xffff) + apdu.res_apdu_data = &ch_certificate_start; + apdu.res_apdu_data_len = ((apdu.res_apdu_data[2] << 8) | apdu.res_apdu_data[3]); + if (apdu.res_apdu_data_len == 0xffff) { - res_APDU_pointer = NULL; + apdu.res_apdu_data_len = 0; GPG_NO_RECORD (); } else - /* Add length of (tag+len) and status word (0x9000) at the end */ - res_APDU_size += 4 + 2; + /* Add length of (tag+len) */ + apdu.res_apdu_data_len += 4; } else +#endif { const struct do_table_entry *do_p = get_do_entry (tag); @@ -1266,9 +1352,8 @@ gpg_do_get_data (uint16_t tag, int with_tag) GPG_SECURITY_FAILURE (); else { - *res_p++ = 0x90; - *res_p++ = 0x00; res_APDU_size = res_p - res_APDU; + GPG_SUCCESS (); } } else @@ -1307,8 +1392,11 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) flash_do_release (*do_data_p); if (len == 0) - /* make DO empty */ - *do_data_p = NULL; + { + /* make DO empty */ + *do_data_p = NULL; + GPG_SUCCESS (); + } else if (len > 255) GPG_MEMORY_FAILURE (); else @@ -1319,6 +1407,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) GPG_MEMORY_FAILURE (); else { + *do_data_p = NULL; *do_data_p = flash_do_write (nr, data, len); if (*do_data_p) GPG_SUCCESS (); @@ -1402,8 +1491,8 @@ gpg_do_public_key (uint8_t kk_byte) *res_p++ = 0x01; *res_p++ = 0x00; *res_p++ = 0x01; /* Success */ - *res_p++ = 0x90; *res_p++ = 0x00; res_APDU_size = res_p - res_APDU; + GPG_SUCCESS (); } DEBUG_INFO ("done.\r\n"); @@ -1433,6 +1522,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) if (data != NULL) { + *do_data_p = NULL; *do_data_p = flash_do_write (nr, data, size); if (*do_data_p == NULL) flash_warning ("DO WRITE ERROR"); @@ -1440,3 +1530,78 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) else *do_data_p = NULL; } + +#ifdef KEYGEN_SUPPORT +void +gpg_do_keygen (uint8_t kk_byte) +{ + enum kind_of_key kk; + const uint8_t *keystring_admin; + const uint8_t *p_q_modulus; + const uint8_t *p_q; + const uint8_t *modulus; + int r; + + DEBUG_INFO ("Keygen\r\n"); + DEBUG_BYTE (kk_byte); + + if (kk_byte == 0xb6) + kk = GPG_KEY_FOR_SIGNING; + else if (kk_byte == 0xb8) + kk = GPG_KEY_FOR_DECRYPTION; + else /* 0xa4 */ + kk = GPG_KEY_FOR_AUTHENTICATION; + + if (admin_authorized == BY_ADMIN) + keystring_admin = keystring_md_pw3; + else + keystring_admin = NULL; + + p_q_modulus = rsa_genkey (); + if (p_q_modulus == NULL) + { + GPG_MEMORY_FAILURE (); + return; + } + + p_q = p_q_modulus; + modulus = p_q_modulus + KEY_CONTENT_LEN; + + r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN, + keystring_admin, modulus); + free ((uint8_t *)p_q_modulus); + if (r < 0) + { + GPG_ERROR (); + return; + } + + DEBUG_INFO ("Calling gpg_do_public_key...\r\n"); + + if (kk == GPG_KEY_FOR_SIGNING) + { + const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); + uint8_t keystring[KEYSTRING_MD_SIZE]; + const uint8_t *ks; + + /* GnuPG expects it's ready for signing. */ + /* Don't call ac_reset_pso_cds here, but load the private key */ + + if (ks_pw1) + ks = ks_pw1+1; + else + { + const uint8_t * pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1; + + s2k (BY_USER, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring); + ks = keystring; + } + + gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, ks); + } + else + ac_reset_other (); + + gpg_do_public_key (kk_byte); +} +#endif diff --git a/src/openpgp.c b/src/openpgp.c index 253de43..867e722 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -1,7 +1,7 @@ /* * openpgp.c -- OpenPGP card protocol support * - * Copyright (C) 2010, 2011 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -25,15 +25,24 @@ #include "ch.h" #include "hal.h" #include "gnuk.h" +#include "sys.h" #include "openpgp.h" -#include "polarssl/config.h" -#include "polarssl/sha1.h" +#include "sha256.h" + +#define ADMIN_PASSWD_MINLEN 8 + +#define CLS(a) a.cmd_apdu_head[0] +#define INS(a) a.cmd_apdu_head[1] +#define P1(a) a.cmd_apdu_head[2] +#define P2(a) a.cmd_apdu_head[3] #define INS_VERIFY 0x20 #define INS_CHANGE_REFERENCE_DATA 0x24 #define INS_PSO 0x2a #define INS_RESET_RETRY_COUNTER 0x2c #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 +#define INS_EXTERNAL_AUTHENTICATE 0x82 +#define INS_GET_CHALLENGE 0x84 #define INS_INTERNAL_AUTHENTICATE 0x88 #define INS_SELECT_FILE 0xa4 #define INS_READ_BINARY 0xb0 @@ -43,6 +52,9 @@ #define INS_PUT_DATA 0xda #define INS_PUT_DATA_ODD 0xdb /* For key import */ +#define CHALLENGE_LEN 32 +static const uint8_t *challenge; /* Random bytes */ + static const uint8_t select_file_TOP_result[] __attribute__ ((aligned (1))) = { 0x00, 0x00, /* unused */ @@ -62,20 +74,21 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = { }; void -set_res_apdu (uint8_t sw1, uint8_t sw2) +set_res_sw (uint8_t sw1, uint8_t sw2) { - res_APDU_size = 2; - res_APDU[0] = sw1; - res_APDU[1] = sw2; + apdu.sw = (sw1 << 8) | sw2; } #define FILE_NONE 0 #define FILE_DF_OPENPGP 1 #define FILE_MF 2 #define FILE_EF_DIR 3 -#define FILE_EF_SERIAL 4 -#define FILE_EF_CH_CERTIFICATE 5 -#define FILE_EF_RANDOM 6 +#define FILE_EF_SERIAL_NO 4 +#define FILE_EF_UPDATE_KEY_0 5 +#define FILE_EF_UPDATE_KEY_1 6 +#define FILE_EF_UPDATE_KEY_2 7 +#define FILE_EF_UPDATE_KEY_3 8 +#define FILE_EF_CH_CERTIFICATE 9 static uint8_t file_selection; @@ -96,25 +109,20 @@ gpg_fini (void) } #if defined(PINPAD_SUPPORT) -/* - * Invoke the thread PIN_MAIN, and let user input PIN string. +/* + * Let user input PIN string. * Return length of the string. * The string itself is in PIN_INPUT_BUFFER. */ static int get_pinpad_input (int msg_code) { - Thread *t; + int r; - t = chThdCreateFromHeap (NULL, THD_WA_SIZE (128), - NORMALPRIO, pin_main, (void *)msg_code); - if (t == NULL) - return -1; - else - { - chThdWait (t); - return pin_input_len; - } + led_blink (LED_START_COMMAND); + r = pinpad_getline (msg_code, MS2ST (8000)); + led_blink (LED_FINISH_COMMAND); + return r; } #endif @@ -122,41 +130,37 @@ static void cmd_verify (void) { int len; - uint8_t p2 = cmd_APDU[3]; + uint8_t p2 = P2 (apdu); int r; - int data_start = 5; const uint8_t *pw; DEBUG_INFO (" - VERIFY\r\n"); DEBUG_BYTE (p2); -#if defined(PINPAD_SUPPORT) - if (cmd_APDU_size == 4) - /* Verification with pinpad */ - { - len = get_pinpad_input (PIN_INPUT_CURRENT); - if (len < 0) - { - GPG_ERROR (); - return; + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; + + if (len == 0) + { /* This is to examine status. */ + if (p2 == 0x81) + r = ac_check_status (AC_PSO_CDS_AUTHORIZED); + else if (p2 == 0x82) + r = ac_check_status (AC_OTHER_AUTHORIZED); + else + r = ac_check_status (AC_ADMIN_AUTHORIZED); + + if (r) + GPG_SUCCESS (); /* If authentication done already, return success. */ + else + { /* If not, return retry counter, encoded. */ + r = gpg_pw_get_retry_counter (p2); + set_res_sw (0x63, 0xc0 | (r&0x0f)); } - pw = pin_input_buffer; - } - else -#endif - { - len = cmd_APDU[4]; - if (len == 0) /* extended length */ - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - - pw = &cmd_APDU[data_start]; + return; } - + /* This is real authentication. */ if (p2 == 0x81) r = verify_pso_cds (pw, len); else if (p2 == 0x82) @@ -236,73 +240,33 @@ cmd_change_password (void) uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t new_ks0[KEYSTRING_MD_SIZE+1]; uint8_t *new_ks = &new_ks0[1]; - uint8_t p2 = cmd_APDU[3]; + uint8_t p1 = P1 (apdu); /* 0: change (old+new), 1: exchange (new) */ + uint8_t p2 = P2 (apdu); int len; - const uint8_t *pw; - const uint8_t *newpw; + uint8_t *pw, *newpw; int pw_len, newpw_len; int who = p2 - 0x80; + int who_old; int r; DEBUG_INFO ("Change PW\r\n"); DEBUG_BYTE (who); -#if defined(PINPAD_SUPPORT) - if (cmd_APDU_size == 4) - /* Modification with pinpad */ + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; + + if (p1 != 0) { - pw_len = get_pinpad_input (PIN_INPUT_CURRENT); - if (pw_len < 0) - { - GPG_ERROR (); - return; - } - - pw = &cmd_APDU[5]; - memcpy (&cmd_APDU[5], pin_input_buffer, pw_len); - newpw = pw + pw_len; - - newpw_len = get_pinpad_input (PIN_INPUT_NEW); - if (newpw_len < 0) - { - GPG_ERROR (); - return; - } - - memcpy (&cmd_APDU[5]+pw_len, pin_input_buffer, newpw_len); - - len = get_pinpad_input (PIN_INPUT_CONFIRM); - if (len < 0) - { - GPG_ERROR (); - return; - } - - if (len != newpw_len || memcmp (newpw, pin_input_buffer, len) != 0) - { - GPG_SECURITY_FAILURE (); - return; - } - - len = cmd_APDU[4] = pw_len + newpw_len; - } - else -#endif - { - len = cmd_APDU[4]; - pw = &cmd_APDU[5]; - if (len == 0) /* extended length */ - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - pw += 2; - } + GPG_FUNCTION_NOT_SUPPORTED (); + return; } if (who == BY_USER) /* PW1 */ { const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); - pw_len = verify_user_0 (pw, len, -1, ks_pw1); + pw_len = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, len, -1, ks_pw1); + who_old = who; if (pw_len < 0) { @@ -318,8 +282,18 @@ cmd_change_password (void) } else { + const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); + newpw = pw + pw_len; newpw_len = len - pw_len; + + /* Check length of password for admin-less mode. */ + if (ks_pw3 == NULL && newpw_len < ADMIN_PASSWD_MINLEN) + { + DEBUG_INFO ("new password length is too short."); + GPG_CONDITION_NOT_SATISFIED (); + return; + } } } else /* PW3 (0x83) */ @@ -342,15 +316,23 @@ cmd_change_password (void) { newpw = pw + pw_len; newpw_len = len - pw_len; - gpg_set_pw3 (newpw, newpw_len); + if (newpw_len == 0 && admin_authorized == BY_ADMIN) + { + newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3); + memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len); + gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0); + } + else + gpg_set_pw3 (newpw, newpw_len); + who_old = admin_authorized; } } - sha1 (pw, pw_len, old_ks); - sha1 (newpw, newpw_len, new_ks); + s2k (who_old, pw, pw_len, old_ks); + s2k (who, newpw, newpw_len, new_ks); new_ks0[0] = newpw_len; - r = gpg_change_keystring (who, old_ks, who, new_ks); + r = gpg_change_keystring (who_old, old_ks, who, new_ks); if (r <= -2) { DEBUG_INFO ("memory error.\r\n"); @@ -366,6 +348,8 @@ cmd_change_password (void) gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n"); GPG_SUCCESS (); } @@ -374,6 +358,8 @@ cmd_change_password (void) gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); ac_reset_pso_cds (); ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n"); GPG_SUCCESS (); } @@ -385,10 +371,33 @@ cmd_change_password (void) } } + +#define USER_S2K_MAGIC "\xffUSER\r\n" +#define RESETCODE_S2K_MAGIC "\xffRESET\r\n" + +void +s2k (int who, const unsigned char *input, unsigned int ilen, + unsigned char output[32]) +{ + sha256_context ctx; + + sha256_start (&ctx); + sha256_update (&ctx, input, ilen); + if (who == BY_USER) + sha256_update (&ctx, (unsigned char *)USER_S2K_MAGIC, + sizeof (USER_S2K_MAGIC)); + else if (who == BY_RESETCODE) + sha256_update (&ctx, (unsigned char *)RESETCODE_S2K_MAGIC, + sizeof (RESETCODE_S2K_MAGIC)); + /* Not add any for BY_ADMIN */ + sha256_finish (&ctx, output); +} + + static void cmd_reset_user_password (void) { - uint8_t p1 = cmd_APDU[2]; + uint8_t p1 = P1 (apdu); int len; const uint8_t *pw; const uint8_t *newpw; @@ -400,61 +409,8 @@ cmd_reset_user_password (void) DEBUG_INFO ("Reset PW1\r\n"); DEBUG_BYTE (p1); -#if defined(PINPAD_SUPPORT) - if (cmd_APDU_size == 4) - /* Modification with pinpad */ - { - if (p1 == 0x00) /* by User with Reseting Code */ - { - pw_len = get_pinpad_input (PIN_INPUT_CURRENT); - if (pw_len < 0) - { - GPG_ERROR (); - return; - } - - memcpy (&cmd_APDU[5], pin_input_buffer, pw_len); - } - else - pw_len = 0; - - pw = &cmd_APDU[5]; - newpw = pw + pw_len; - newpw_len = get_pinpad_input (PIN_INPUT_NEW); - if (newpw_len < 0) - { - GPG_ERROR (); - return; - } - - memcpy (&cmd_APDU[5]+pw_len, pin_input_buffer, newpw_len); - - len = get_pinpad_input (PIN_INPUT_CONFIRM); - if (len < 0) - { - GPG_ERROR (); - return; - } - - if (len != newpw_len || memcmp (newpw, pin_input_buffer, len) != 0) - { - GPG_SECURITY_FAILURE (); - return; - } - - len = cmd_APDU[4] = pw_len + newpw_len; - } - else -#endif - { - len = cmd_APDU[4]; - pw = &cmd_APDU[5]; - if (len == 0) /* extended length */ - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - pw += 2; - } - } + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; if (p1 == 0x00) /* by User with Reseting Code */ { @@ -478,8 +434,8 @@ cmd_reset_user_password (void) pw_len = ks_rc[0]; newpw = pw + pw_len; newpw_len = len - pw_len; - sha1 (pw, pw_len, old_ks); - sha1 (newpw, newpw_len, new_ks); + s2k (BY_RESETCODE, pw, pw_len, old_ks); + s2k (BY_USER, newpw, newpw_len, new_ks); new_ks0[0] = newpw_len; r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks); if (r <= -2) @@ -503,6 +459,8 @@ cmd_reset_user_password (void) KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); gpg_pw_reset_err_counter (PW_ERR_RC); gpg_pw_reset_err_counter (PW_ERR_PW1); GPG_SUCCESS (); @@ -510,8 +468,11 @@ cmd_reset_user_password (void) else { DEBUG_INFO ("done.\r\n"); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); ac_reset_pso_cds (); ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); gpg_pw_reset_err_counter (PW_ERR_RC); gpg_pw_reset_err_counter (PW_ERR_PW1); GPG_SUCCESS (); @@ -530,7 +491,7 @@ cmd_reset_user_password (void) newpw_len = len; newpw = pw; - sha1 (newpw, newpw_len, new_ks); + s2k (BY_USER, newpw, newpw_len, new_ks); new_ks0[0] = newpw_len; r = gpg_change_keystring (admin_authorized, old_ks, BY_USER, new_ks); if (r <= -2) @@ -550,14 +511,19 @@ cmd_reset_user_password (void) KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); gpg_pw_reset_err_counter (PW_ERR_PW1); GPG_SUCCESS (); } else { DEBUG_INFO ("done.\r\n"); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); ac_reset_pso_cds (); ac_reset_other (); + if (admin_authorized == BY_USER) + ac_reset_admin (); gpg_pw_reset_err_counter (PW_ERR_PW1); GPG_SUCCESS (); } @@ -576,16 +542,9 @@ cmd_put_data (void) if (file_selection != FILE_DF_OPENPGP) GPG_NO_RECORD(); - tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]); - len = cmd_APDU_size - 5; - data = &cmd_APDU[5]; - if (len >= 256) - /* extended Lc */ - { - data += 2; - len -= 2; - } - + tag = ((P1 (apdu)<<8) | P2 (apdu)); + len = apdu.cmd_apdu_data_len; + data = apdu.cmd_apdu_data; gpg_do_put_data (tag, data, len); } @@ -593,58 +552,135 @@ static void cmd_pgp_gakp (void) { DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n"); - DEBUG_BYTE (cmd_APDU[2]); + DEBUG_BYTE (P1 (apdu)); - if (cmd_APDU[2] == 0x81) + if (P1 (apdu) == 0x81) /* Get public key */ - { - if (cmd_APDU[4] == 0) - gpg_do_public_key (cmd_APDU[7]); - else - gpg_do_public_key (cmd_APDU[5]); - } + gpg_do_public_key (apdu.cmd_apdu_data[0]); else - { /* Generate key pair */ + { if (!ac_check_status (AC_ADMIN_AUTHORIZED)) GPG_SECURITY_FAILURE (); - - /* XXX: Not yet supported */ - GPG_ERROR (); +#ifdef KEYGEN_SUPPORT + /* Generate key pair */ + gpg_do_keygen (apdu.cmd_apdu_data[0]); +#else + GPG_FUNCTION_NOT_SUPPORTED (); +#endif } } +const uint8_t * +gpg_get_firmware_update_key (uint8_t keyno) +{ + extern uint8_t _updatekey_store; + const uint8_t *p; + + p = &_updatekey_store + keyno * KEY_CONTENT_LEN; + return p; +} + +#ifdef CERTDO_SUPPORT +#define FILEID_CH_CERTIFICATE_IS_VALID 1 +#else +#define FILEID_CH_CERTIFICATE_IS_VALID 0 +#endif + static void cmd_read_binary (void) { + int is_short_EF = (P1 (apdu) & 0x80) != 0; + uint8_t file_id; + const uint8_t *p; + uint16_t offset; + DEBUG_INFO (" - Read binary\r\n"); - if (file_selection == FILE_EF_SERIAL) + if (is_short_EF) + file_id = (P1 (apdu) & 0x1f); + else + file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO; + + if ((!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE) + || file_id > FILEID_CH_CERTIFICATE) { - if (cmd_APDU[3] >= 6) - GPG_BAD_P0_P1 (); - else - { - gpg_do_get_data (0x004f, 1); /* AID */ - res_APDU[0] = 0x5a; - } + GPG_NO_FILE (); + return; + } + + if (is_short_EF) + { + file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO; + offset = P2 (apdu); } else - GPG_NO_RECORD(); + offset = (P1 (apdu) << 8) | P2 (apdu); + + if (file_id == FILEID_SERIAL_NO) + { + if (offset != 0) + GPG_BAD_P1_P2 (); + else + { + gpg_do_get_data (0x004f, 1); /* Get AID... */ + res_APDU[0] = 0x5a; /* ... and overwrite the first byte of data. */ + } + return; + } + + if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3) + { + if (offset != 0) + GPG_MEMORY_FAILURE (); + else + { + p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0); + res_APDU_size = KEY_CONTENT_LEN; + memcpy (res_APDU, p, KEY_CONTENT_LEN); + GPG_SUCCESS (); + } + } +#if defined(CERTDO_SUPPORT) + else /* file_id == FILEID_CH_CERTIFICATE */ + { + uint16_t len = 256; + + p = &ch_certificate_start; + if (offset >= FLASH_CH_CERTIFICATE_SIZE) + GPG_MEMORY_FAILURE (); + else + { + if (offset + len >= FLASH_CH_CERTIFICATE_SIZE) + len = FLASH_CH_CERTIFICATE_SIZE - offset; + + res_APDU_size = len; + memcpy (res_APDU, p + offset, len); + GPG_SUCCESS (); + } + } +#endif } static void cmd_select_file (void) { - if (cmd_APDU[2] == 4) /* Selection by DF name: it must be OpenPGP card */ + if (P1 (apdu) == 4) /* Selection by DF name */ { DEBUG_INFO (" - select DF by name\r\n"); - /* - * P2 == 0, LC=6, name = D2 76 00 01 24 01 - */ + /* name = D2 76 00 01 24 01 */ + if (apdu.cmd_apdu_data_len != 6 + || memcmp (openpgpcard_aid, apdu.cmd_apdu_data, 6) != 0) + { + DEBUG_SHORT (apdu.cmd_apdu_data_len); + DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); + + GPG_NO_FILE (); + return; + } file_selection = FILE_DF_OPENPGP; - if (cmd_APDU[3] == 0x0c) /* No FCI */ + if ((P2 (apdu) & 0x0c) == 0x0c) /* No FCI */ GPG_SUCCESS (); else { @@ -654,23 +690,24 @@ cmd_select_file (void) res_APDU[1] = 0x12; res_APDU[2] = 0x84; /* overwrite: DF name */ res_APDU_size += 2; + GPG_SUCCESS (); } } - else if (cmd_APDU[4] == 2 - && cmd_APDU[5] == 0x2f && cmd_APDU[6] == 0x02) + else if (apdu.cmd_apdu_data_len == 2 + && apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02) { DEBUG_INFO (" - select 0x2f02 EF\r\n"); /* * MF.EF-GDO -- Serial number of the card and name of the owner */ GPG_SUCCESS (); - file_selection = FILE_EF_SERIAL; + file_selection = FILE_EF_SERIAL_NO; } - else if (cmd_APDU[4] == 2 - && cmd_APDU[5] == 0x3f && cmd_APDU[6] == 0x00) + else if (apdu.cmd_apdu_data_len == 2 + && apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00) { DEBUG_INFO (" - select ROOT MF\r\n"); - if (cmd_APDU[3] == 0x0c) + if (P2 (apdu) == 0x0c) { GPG_SUCCESS (); } @@ -678,12 +715,11 @@ cmd_select_file (void) { int len = sizeof (select_file_TOP_result); - res_APDU_size = 2 + len; + res_APDU_size = len; memcpy (res_APDU, select_file_TOP_result, len); res_APDU[2] = (data_objects_number_of_bytes & 0xff); res_APDU[3] = (data_objects_number_of_bytes >> 8); - res_APDU[len] = 0x90; - res_APDU[len+1] = 0x00; + GPG_SUCCESS (); } file_selection = FILE_MF; @@ -701,7 +737,7 @@ cmd_select_file (void) static void cmd_get_data (void) { - uint16_t tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]); + uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu)); DEBUG_INFO (" - Get Data\r\n"); @@ -714,20 +750,14 @@ cmd_get_data (void) static void cmd_pso (void) { - int len = cmd_APDU[4]; - int data_start = 5; + int len = apdu.cmd_apdu_data_len; int r; - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - DEBUG_INFO (" - PSO: "); DEBUG_WORD ((uint32_t)&r); + DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); - if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a) + if (P1 (apdu) == 0x9e && P2 (apdu) == 0x9a) { if (!ac_check_status (AC_PSO_CDS_AUTHORIZED)) { @@ -736,23 +766,24 @@ cmd_pso (void) return; } - if (cmd_APDU_size != 7 + 34 + 2 /* MD5 */ - /* Header (with Extended Lc)=7, size of digestInfo, and Le=2-byte */ - && cmd_APDU_size != 7 + 35 + 2 /* SHA1 / RIPEMD-160 */ - && cmd_APDU_size != 7 + 47 + 2 /* SHA224 */ - && cmd_APDU_size != 7 + 51 + 2 /* SHA256 */ - && cmd_APDU_size != 7 + 67 + 2 /* SHA384 */ - && cmd_APDU_size != 7 + 83 + 2) /* SHA512 */ + /* Check size of digestInfo */ + if (len != 34 /* MD5 */ + && len != 35 /* SHA1 / RIPEMD-160 */ + && len != 47 /* SHA224 */ + && len != 51 /* SHA256 */ + && len != 67 /* SHA384 */ + && len != 83) /* SHA512 */ { DEBUG_INFO (" wrong length: "); - DEBUG_SHORT (cmd_APDU_size); + DEBUG_SHORT (len); GPG_ERROR (); } else { - DEBUG_SHORT (len); /* Should be cmd_APDU_size - 8 [- 1] */ + DEBUG_SHORT (len); + DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN); - r = rsa_sign (&cmd_APDU[data_start], res_APDU, len, + r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len, &kd[GPG_KEY_FOR_SIGNING]); if (r < 0) { @@ -764,9 +795,10 @@ cmd_pso (void) gpg_increment_digital_signature_counter (); } } - else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86) + else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86) { DEBUG_SHORT (len); + DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN); if (!ac_check_status (AC_OTHER_AUTHORIZED)) { @@ -776,41 +808,40 @@ cmd_pso (void) } /* Skip padding 0x00 */ - data_start++; len--; - r = rsa_decrypt (&cmd_APDU[data_start], res_APDU, len, - &kd[GPG_KEY_FOR_DECRYPTION]); - if (r < 0) - GPG_ERROR (); + if (len != KEY_CONTENT_LEN) + GPG_CONDITION_NOT_SATISFIED (); + else + { + r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len, + &kd[GPG_KEY_FOR_DECRYPTION]); + if (r < 0) + GPG_ERROR (); + } } else { DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[2]); + DEBUG_BYTE (P1 (apdu)); DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[3]); + DEBUG_BYTE (P2 (apdu)); GPG_ERROR (); } DEBUG_INFO ("PSO done.\r\n"); } + +#define MAX_DIGEST_INFO_LEN 102 /* 40% */ static void cmd_internal_authenticate (void) { - int len = cmd_APDU[4]; - int data_start = 5; + int len = apdu.cmd_apdu_data_len; int r; - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n"); - if (cmd_APDU[2] == 0x00 && cmd_APDU[3] == 0x00) + if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00) { DEBUG_SHORT (len); @@ -821,7 +852,14 @@ cmd_internal_authenticate (void) return; } - r = rsa_sign (&cmd_APDU[data_start], res_APDU, len, + if (len > MAX_DIGEST_INFO_LEN) + { + DEBUG_INFO ("input is too long."); + GPG_CONDITION_NOT_SATISFIED (); + return; + } + + r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len, &kd[GPG_KEY_FOR_AUTHENTICATION]); if (r < 0) GPG_ERROR (); @@ -829,32 +867,26 @@ cmd_internal_authenticate (void) else { DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[2]); + DEBUG_BYTE (P1 (apdu)); DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[3]); + DEBUG_BYTE (P2 (apdu)); GPG_ERROR (); } DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n"); } +#define MBD_OPRATION_WRITE 0 +#define MBD_OPRATION_UPDATE 1 static void -cmd_update_binary (void) +modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len) { - int len = cmd_APDU[4]; - int data_start = 5; + uint8_t file_id; uint16_t offset; + int is_short_EF = (p1 & 0x80) != 0; int r; - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - - DEBUG_INFO (" - UPDATE BINARY\r\n"); - if (!ac_check_status (AC_ADMIN_AUTHORIZED)) { DEBUG_INFO ("security error."); @@ -862,42 +894,52 @@ cmd_update_binary (void) return; } - if ((cmd_APDU[2] & 0x80)) - if ((cmd_APDU[2] & 0x7f) <= FILEID_RANDOM) - { - file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f); - r = flash_erase_binary (file_selection - FILE_EF_CH_CERTIFICATE); - if (r < 0) - { - DEBUG_INFO ("memory error.\r\n"); - GPG_MEMORY_FAILURE (); - return; - } - - offset = 0; - } - else - { - GPG_NO_FILE (); - return; - } + if (is_short_EF) + file_id = (p1 & 0x1f); else - { - if (file_selection != FILE_EF_CH_CERTIFICATE - && file_selection != FILE_EF_RANDOM) - { - GPG_COMMAND_NOT_ALLOWED (); - return; - } + file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO; - offset = (cmd_APDU[2] << 8) | cmd_APDU[3]; + if (!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE) + { + GPG_NO_FILE (); + return; } + if (op == MBD_OPRATION_UPDATE && file_id != FILEID_CH_CERTIFICATE) + { + GPG_CONDITION_NOT_SATISFIED (); + return; + } + + if (file_id > FILEID_CH_CERTIFICATE) + { + GPG_NO_FILE (); + return; + } + + if (is_short_EF) + { + file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO; + offset = p2; + + if (op == MBD_OPRATION_UPDATE) + { + r = flash_erase_binary (file_id); + if (r < 0) + { + DEBUG_INFO ("memory error.\r\n"); + GPG_MEMORY_FAILURE (); + return; + } + } + } + else + offset = (p1 << 8) | p2; + DEBUG_SHORT (len); DEBUG_SHORT (offset); - r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE, - &cmd_APDU[data_start], len, offset); + r = flash_write_binary (file_id, apdu.cmd_apdu_data, len, offset); if (r < 0) { DEBUG_INFO ("memory error.\r\n"); @@ -906,71 +948,103 @@ cmd_update_binary (void) } GPG_SUCCESS (); +} + + +#if defined(CERTDO_SUPPORT) +static void +cmd_update_binary (void) +{ + int len = apdu.cmd_apdu_data_len; + + DEBUG_INFO (" - UPDATE BINARY\r\n"); + modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len); DEBUG_INFO ("UPDATE BINARY done.\r\n"); } +#endif static void cmd_write_binary (void) { - int len = cmd_APDU[4]; - int data_start = 5; - uint16_t offset; - int r; - - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } + int len = apdu.cmd_apdu_data_len; + int i; + const uint8_t *p; DEBUG_INFO (" - WRITE BINARY\r\n"); + modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len); - if (!ac_check_status (AC_ADMIN_AUTHORIZED)) + for (i = 0; i < 4; i++) + { + p = gpg_get_firmware_update_key (i); + if (p[0] != 0x00 || p[1] != 0x00) /* still valid */ + break; + } + + if (i == 4) /* all update keys are removed */ + { + p = gpg_get_firmware_update_key (0); + flash_erase_page ((uint32_t)p); + } + + DEBUG_INFO ("WRITE BINARY done.\r\n"); +} + + +static void +cmd_external_authenticate (void) +{ + const uint8_t *pubkey; + const uint8_t *signature = apdu.cmd_apdu_data; + int len = apdu.cmd_apdu_data_len; + uint8_t keyno = P2 (apdu); + int r; + + DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n"); + + if (keyno >= 4) + { + GPG_CONDITION_NOT_SATISFIED (); + return; + } + + pubkey = gpg_get_firmware_update_key (keyno); + if (len != 256 + || (pubkey[0] == 0xff && pubkey[1] == 0xff) /* not registered */ + || (pubkey[0] == 0x00 && pubkey[1] == 0x00) /* removed */) + { + GPG_CONDITION_NOT_SATISFIED (); + return; + } + + r = rsa_verify (pubkey, challenge, signature); + random_bytes_free (challenge); + challenge = NULL; + + if (r < 0) { - DEBUG_INFO ("security error."); GPG_SECURITY_FAILURE (); return; } - if ((cmd_APDU[2] & 0x80)) - if ((cmd_APDU[2] & 0x7f) <= FILEID_SERIAL_NO) - { - file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f); - offset = 0; - } - else - { - GPG_NO_FILE (); - return; - } - else - { - if (file_selection != FILE_EF_CH_CERTIFICATE - && file_selection != FILE_EF_RANDOM - && file_selection != FILE_EF_SERIAL) - { - GPG_COMMAND_NOT_ALLOWED (); - return; - } + chThdTerminate (chThdSelf ()); + set_res_sw (0xff, 0xff); + DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n"); +} - offset = (cmd_APDU[2] << 8) | cmd_APDU[3]; - } +static void +cmd_get_challenge (void) +{ + DEBUG_INFO (" - GET CHALLENGE\r\n"); - DEBUG_SHORT (len); - DEBUG_SHORT (offset); - - r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE, - &cmd_APDU[data_start], len, offset); - if (r < 0) - { - DEBUG_INFO ("memory error.\r\n"); - GPG_MEMORY_FAILURE (); - return; - } + if (challenge) + random_bytes_free (challenge); + challenge = random_bytes_get (); + memcpy (res_APDU, challenge, CHALLENGE_LEN); + res_APDU_size = CHALLENGE_LEN; GPG_SUCCESS (); - DEBUG_INFO ("WRITE BINARY done.\r\n"); + DEBUG_INFO ("GET CHALLENGE done.\r\n"); } @@ -986,12 +1060,17 @@ const struct command cmds[] = { { INS_PSO, cmd_pso }, { INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, + { INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */ + cmd_external_authenticate }, + { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */ { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate }, { INS_SELECT_FILE, cmd_select_file }, { INS_READ_BINARY, cmd_read_binary }, { INS_GET_DATA, cmd_get_data }, - { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */ + { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */ +#if defined(CERTDO_SUPPORT) { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */ +#endif { INS_PUT_DATA, cmd_put_data }, { INS_PUT_DATA_ODD, cmd_put_data }, }; @@ -1001,7 +1080,7 @@ static void process_command_apdu (void) { int i; - uint8_t cmd = cmd_APDU[1]; + uint8_t cmd = INS (apdu); for (i = 0; i < NUM_CMDS; i++) if (cmds[i].command == cmd) @@ -1028,17 +1107,101 @@ GPGthread (void *arg) while (!chThdShouldTerminate ()) { - chEvtWaitOne (ALL_EVENTS); + eventmask_t m = chEvtWaitOne (ALL_EVENTS); +#if defined(PINPAD_SUPPORT) + int len, pw_len, newpw_len; +#endif DEBUG_INFO ("GPG!: "); - res_APDU_pointer = NULL; /* default */ - - if (icc_data_size != 0) + if (m == EV_VERIFY_CMD_AVAILABLE) { - process_command_apdu (); - chEvtSignal (icc_thread, EV_EXEC_FINISHED); +#if defined(PINPAD_SUPPORT) + if (INS (apdu) != INS_VERIFY) + { + GPG_CONDITION_NOT_SATISFIED (); + goto done; + } + + pw_len = get_pinpad_input (PIN_INPUT_CURRENT); + if (pw_len < 0) + { + GPG_ERROR (); + goto done; + } + memcpy (apdu.cmd_apdu_data, pin_input_buffer, pw_len); + apdu.cmd_apdu_data_len = pw_len; +#else + GPG_ERROR (); + goto done; +#endif } + else if (m == EV_MODIFY_CMD_AVAILABLE) + { +#if defined(PINPAD_SUPPORT) + uint8_t bConfirmPIN = apdu.cmd_apdu_data[5]; + uint8_t *p = apdu.cmd_apdu_data; + + if (INS (apdu) != INS_CHANGE_REFERENCE_DATA + && INS (apdu) != INS_RESET_RETRY_COUNTER + && INS (apdu) != INS_PUT_DATA) + { + GPG_CONDITION_NOT_SATISFIED (); + goto done; + } + + if ((bConfirmPIN & 2)) /* Require old PIN */ + { + pw_len = get_pinpad_input (PIN_INPUT_CURRENT); + if (pw_len < 0) + { + GPG_ERROR (); + goto done; + } + memcpy (p, pin_input_buffer, pw_len); + p += pw_len; + } + else + pw_len = 0; + + newpw_len = get_pinpad_input (PIN_INPUT_NEW); + if (newpw_len < 0) + { + GPG_ERROR (); + goto done; + } + memcpy (p, pin_input_buffer, newpw_len); + + if ((bConfirmPIN & 1)) /* New PIN twice */ + { + len = get_pinpad_input (PIN_INPUT_CONFIRM); + if (len < 0) + { + GPG_ERROR (); + goto done; + } + + if (len != newpw_len || memcmp (p, pin_input_buffer, len) != 0) + { + GPG_SECURITY_FAILURE (); + goto done; + } + } + + apdu.cmd_apdu_data_len = pw_len + newpw_len; +#else + GPG_ERROR (); + goto done; +#endif + } + else if (m == EV_NOP) + continue; + + led_blink (LED_START_COMMAND); + process_command_apdu (); + led_blink (LED_FINISH_COMMAND); + done: + chEvtSignal (icc_thread, EV_EXEC_FINISHED); } gpg_fini (); diff --git a/src/openpgp.h b/src/openpgp.h index 0d039c9..b8693b9 100644 --- a/src/openpgp.h +++ b/src/openpgp.h @@ -1,10 +1,12 @@ -#define GPG_MEMORY_FAILURE() set_res_apdu (0x65, 0x81) -#define GPG_SECURITY_FAILURE() set_res_apdu (0x69, 0x82) -#define GPG_SECURITY_AUTH_BLOCKED() set_res_apdu (0x69, 0x83) -#define GPG_COMMAND_NOT_ALLOWED() set_res_apdu (0x69, 0x86) -#define GPG_NO_FILE() set_res_apdu (0x6a, 0x82) -#define GPG_NO_RECORD() set_res_apdu (0x6a, 0x88) -#define GPG_BAD_P0_P1() set_res_apdu (0x6b, 0x00) -#define GPG_NO_INS() set_res_apdu (0x6d, 0x00) -#define GPG_ERROR() set_res_apdu (0x6f, 0x00) -#define GPG_SUCCESS() set_res_apdu (0x90, 0x00) +#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81) +#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82) +#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83) +#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85) +#define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) +#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81) +#define GPG_NO_FILE() set_res_sw (0x6a, 0x82) +#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88) +#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00) +#define GPG_NO_INS() set_res_sw (0x6d, 0x00) +#define GPG_ERROR() set_res_sw (0x6f, 0x00) +#define GPG_SUCCESS() set_res_sw (0x90, 0x00) diff --git a/src/pin-cir.c b/src/pin-cir.c index f512b94..75c8f62 100644 --- a/src/pin-cir.c +++ b/src/pin-cir.c @@ -27,13 +27,41 @@ #include "board.h" #include "gnuk.h" -#if 0 +#ifdef DEBUG #define DEBUG_CIR 1 #endif uint8_t pin_input_buffer[MAX_PIN_CHARS]; uint8_t pin_input_len; +/* + * Supported/tested TV controllers: + * + * Controller of Toshiba REGZA + * Controller of Sony BRAVIA + * Controller of Sharp AQUOS + * Dell Wireless Travel Remote MR425 + * + * The code supports RC-5 protocol in fact, but I don't have any + * controller at hand which I can test with, so I don't have any data + * for controller of RC-5. + * + * Current code assumes following mapping: + * + * -------------------------------------- + * Protocol Controller + * -------------------------------------- + * RC-6 Dell MR425 + * NEC Toshiba REGZA + * Sharp Sharp AQUOS + * Sony Sony BRAVIA + * -------------------------------------- + * + * In future, when I will have other controllers, this mapping will be + * (should be) configurable, at compile time at least, preferably at + * runtime. + */ + /* * Philips RC-5 Protocol: 14-bit (MSB first) * @@ -69,18 +97,26 @@ uint8_t pin_input_len; */ /* - * PB0 / TIM3_CH3 + * The implementation note of CIR signal decoding (on STM32). + * + * (1) Use EXTI interrupt to detect the first edge of signal. + * (2) Use Timer (with PWM input mode) to measure timings of square wave. + * + */ + +/* + * Timer settings. + * + * See THE reference manual (RM0008) section 15.3.6 PWM input mode. * * 72MHz - * * Prescaler = 72 * * 1us * - * - * TIM3_CR1 - * CKD = 10 (sampling x4) - * ARPE = 0 (not buffered) + * TIMx_CR1 + * CKD = 00 (tDTS = tCK_INT) + * ARPE = 1 (buffered) * CMS = 00 (up counter) * DIR = 0 (up counter) * OPM = 0 (up counter) @@ -88,13 +124,13 @@ uint8_t pin_input_len; * UDIS = 0 (UEV (update event) enabled) * CEN = 1 (counter enable) * - * TIM3_CR2 + * TIMx_CR2 * TI1S = 1 (TI1 is XOR of ch1, ch2, ch3) * MMS = 000 (TRGO at Reset) * CCDS = 0 (DMA on capture) * RSVD = 000 * - * TIM3_SMCR + * TIMx_SMCR * ETP = 0 * ECE = 0 * ETPS = 00 @@ -104,61 +140,37 @@ uint8_t pin_input_len; * RSVD = 0 * SMS = 100 (Reset-mode) * - * TIM3_DIER + * TIMx_DIER * - * TIM3_SR + * TIMx_SR * - * TIM3_EGR + * TIMx_EGR * - * TIM3_CCMR1 + * TIMx_CCMR1 * CC1S = 01 (TI1 selected) * CC2S = 10 (TI1 selected) + * IC1F = 1001 (fSAMPLING=fDTS/8, N=8) + * IC2F = 1001 (fSAMPLING=fDTS/8, N=8) * - * TIM3_CCMR2 + * TIMx_CCMR2 * - * TIM3_CCER + * TIMx_CCER * CC2P = 1 (polarity = falling edge: TI1FP1) * CC2E = 1 * CC1P = 0 (polarity = rising edge: TI1FP1) * CC1E = 1 * - * TIM3_CNT - * TIM3_PSC = 71 - * TIM3_ARR = 18000 + * TIMx_CNT + * TIMx_PSC = 71 + * TIMx_ARR = 18000 * - * TIM3_CCR1 period - * TIM3_CCR2 duty + * TIMx_CCR1 period + * TIMx_CCR2 duty * - * TIM3_DCR - * TIM3_DMAR + * TIMx_DCR + * TIMx_DMAR */ -#define PINDISP_TIMEOUT_INTERVAL0 MS2ST(25) -#define PINDISP_TIMEOUT_INTERVAL1 MS2ST(300) - -static void -pindisp (uint8_t c) -{ -#if defined(HAVE_7SEGLED) - switch (c) - { - case 'G': - palWritePort (IOPORT2, 0xa1ff); - break; - case 'P': - palWritePort (IOPORT2, 0x98ff); - break; - case '.': - palWritePort (IOPORT2, 0x7fff); - break; - default: - palWritePort (IOPORT2, 0xffff); - } -#else - (void)c; -#endif -} - #if defined(DEBUG_CIR) static uint16_t intr_ext; static uint16_t intr_trg; @@ -179,14 +191,6 @@ static uint8_t cir_proto; #define CIR_PROTO_NEC 5 #define CIR_PROTO_SHARP 6 -#define CIR_KEY_RC6_ENTER 0x0d /* Mute */ -#define CIR_KEY_RC6_BACKSPACE 0xa4 /* <= */ -#define CIR_KEY_NEC_ENTER 0x3d /* 'kettei' */ -#define CIR_KEY_NEC_BACKSPACE 0x3b /* 'modoru' */ -#define CIR_KEY_SONY_ENTER 0x65 /* 'kettei' */ -#define CIR_KEY_SONY_BACKSPACE 0xa3 /* 'modoru' */ -#define CIR_KEY_SHARP_ENTER 0x0252 /* 'kettei' */ -#define CIR_KEY_SHARP_BACKSPACE 0xe4 /* 'modoru' */ /* CIR_DATA_ZERO: Used for zero-bit handling of RC-5/RC-6 */ static uint8_t cir_data_zero; @@ -196,6 +200,388 @@ static uint8_t cir_seq; static systime_t cir_input_last; #define CIR_PERIOD_INHIBIT_CHATTER 200 /* mili second */ +static void +cir_init (void) +{ + cir_data = 0; + cir_seq = 0; + /* Don't touch cir_proto here */ + cir_ext_enable (); +} + + +#define CH_RETURN 0x0d +#define CH_BACKSPACE 0x08 + +struct codetable { + uint16_t cir_code; + uint8_t char_code; +}; + +/* NOTE: no way to input '0' */ +static const struct codetable +cir_codetable_dell_mr425[] = { + {0x10, '7' }, /* Speaker Louder */ + {0x11, '8' }, /* Speaker Quieter */ + {0x0d, '9' }, /* Speaker Mute */ + {0xce, 'a' }, /* Black triangle UP */ + {0xcf, 'b' }, /* Black triangle DOWN */ + {0x58, 'c' }, /* White triangle UP */ + {0x5a, 'd' }, /* White triangle LEFT */ + {0x5c, CH_RETURN }, /* Check */ + {0x5b, 'e' }, /* White triangle RIGHT */ + {0xa4, CH_BACKSPACE }, /* Back */ + {0x59, 'f' }, /* White triangle DOWN */ + {0x2f, '1' }, /* Rewind */ + {0x2c, '2' }, /* Play / Pause */ + {0x2e, '3' }, /* Forward */ + {0x21, '4' }, /* Skip backward */ + {0x31, '5' }, /* Stop */ + {0x20, '6' }, /* Skip forward */ + + {0, 0} /* <> */ +}; + +#define CIR_ADDR_SHARP_AQUOS 0x028f +static const struct codetable +cir_codetable_aquos[] = { + { 0x0116, ' ' }, /* Power */ + { 0x025e, '0' }, /* d */ + { 0x024e, '1' }, /* 1 */ + { 0x024f, '2' }, /* 2 */ + { 0x0250, '3' }, /* 3 */ + { 0x0251, '4' }, /* 4 */ + { 0x0252, '5' }, /* 5 */ + { 0x0253, '6' }, /* 6 */ + { 0x0254, '7' }, /* 7 */ + { 0x0255, '8' }, /* 8 */ + { 0x0256, '9' }, /* 9 */ + { 0x0257, 'a' }, /* 10/0 */ + { 0x0258, 'b' }, /* 11 */ + { 0x0259, 'c' }, /* 12 */ + { 0x0111, 'd' }, /* Ch ^ */ + { 0x0112, 'e' }, /* Ch v */ + { 0x0114, 'f' }, /* Vol + */ + { 0x0115, 'g' }, /* Vol - */ + { 0x0117, 'h' }, /* Mute */ + { 0x0280, 'i' }, /* BLUE */ + { 0x0281, 'j' }, /* RED */ + { 0x0282, 'k' }, /* GREEN */ + { 0x0283, 'l' }, /* YELLOW */ + { 0x011b, 'm' }, /* DISPLAY CONTROL (gamen hyouji) */ + { 0x01d5, 'n' }, /* DISPLAY SIZE */ + { 0x0157, 'o' }, /* UP */ + { 0x01d7, 'p' }, /* LEFT */ + { 0x01d8, 'q' }, /* RIGHT */ + { 0x0120, 'r' }, /* DOWN */ + { 0x0152, CH_RETURN }, /* Commit (kettei) */ + { 0x01e4, CH_BACKSPACE }, /* Back (modoru) */ + { 0x01f5, 's' }, /* Quit (shuuryou) */ + { 0x0b03, 't' }, /* Rewind (hayamodoshi) */ + { 0x0b01, 'u' }, /* Play (saisei) */ + { 0x0b04, 'v' }, /* Forward (hayaokuri) */ + { 0x0b02, 'w' }, /* Stop (teishi) */ + { 0x028a, 'x' }, /* BS */ + { 0x028b, 'y' }, /* CS */ + { 0x025f, 'z' }, /* Program information (bangumi jouhou) */ + { 0x0260, '\\' }, /* Program table (bangumi hyou) */ + { 0x0118, '|' }, /* Sound channel (onsei kirikae) */ + { 0x028e, '[' }, /* Ground Analog (chijou A) */ + { 0x0289, ']' }, /* Ground Digital (chijou D) */ + + { 0x0b07, '\"' }, /* Feature select (kinou sentaku) */ + { 0x026b, '.' }, /* TV/Radio/Data (terebi/rajio/data) */ + { 0x025a, ',' }, /* 3 code input (3 keta nyuuryoku) */ + { 0x0267, ':' }, /* subtitle (jimaku) */ + { 0x0159, ';' }, /* hold (seishi) */ + + { 0x01c4, 'A' }, /* Menu */ + { 0x011a, 'B' }, /* Off timer */ + { 0x0121, 'C' }, /* CATV */ + { 0x0b05, 'D' }, /* Record */ + { 0x0b06, 'E' }, /* Recording stop */ + { 0x0113, 'F' }, /* Inputs (nyuuryoku kirikae) */ + { 0x0275, 'G' }, /* other programs (ura bangumi) */ + { 0x0266, 'H' }, /* signal control (eizou kirikae) */ + { 0x01e7, 'I' }, /* AV position */ + { 0x027f, 'J' }, /* i.LINK */ + { 0x0b00, 'K' }, /* Recorder power */ + { 0x028f, 'L' }, /* as you like it (okonomi senkyoku) */ + + {0, 0} /* <> */ +}; + +#define CIR_ADDR_TOSHIBA_REGZA 0xbf40 +static const struct codetable +cir_codetable_regza[] = { + { 0x12, ' ' }, /* Power */ + { 0x14, '0' }, /* d (data) */ + { 0x01, '1' }, /* 1 */ + { 0x02, '2' }, /* 2 */ + { 0x03, '3' }, /* 3 */ + { 0x04, '4' }, /* 4 */ + { 0x05, '5' }, /* 5 */ + { 0x06, '6' }, /* 6 */ + { 0x07, '7' }, /* 7 */ + { 0x08, '8' }, /* 8 */ + { 0x09, '9' }, /* 9 */ + { 0x0a, 'a' }, /* 10 */ + { 0x0b, 'b' }, /* 11 */ + { 0x0c, 'c' }, /* 12 */ + { 0x1b, 'd' }, /* Ch ^ */ + { 0x1f, 'e' }, /* Ch v */ + { 0x1a, 'f' }, /* Vol + */ + { 0x1e, 'g' }, /* Vol - */ + { 0x10, 'h' }, /* Mute */ + { 0x73, 'i' }, /* BLUE */ + { 0x74, 'j' }, /* RED */ + { 0x75, 'k' }, /* GREEN */ + { 0x76, 'l' }, /* YELLOW */ + { 0x1c, 'm' }, /* Display control */ + { 0x2b, 'n' }, /* Display size */ + { 0x3e, 'o' }, /* UP */ + { 0x5f, 'p' }, /* LEFT */ + { 0x5b, 'q' }, /* RIGHT */ + { 0x3f, 'r' }, /* DOWN */ + { 0x3d, CH_RETURN }, /* Commit (kettei) */ + { 0x3b, CH_BACKSPACE }, /* Back (modoru) */ + { 0x3c, 's' }, /* Quit (shuuryou) */ + { 0x2c, 't' }, /* << (Rewind) */ + { 0x2d, 'u' }, /* >/|| (Play/Stop) */ + { 0x2e, 'v' }, /* >> (Forward) */ + { 0x2b, 'w' }, /* Stop (teishi) */ + { 0x7c, 'x' }, /* BS */ + { 0x7d, 'y' }, /* CS */ + { 0x71, 'z' }, /* Program information (bangumi setsumei) */ + { 0x77, '\\' }, /* Mini program table (mini bangumihyou) */ + { 0x13, '|' }, /* Sound (onta kirikae) */ + { 0x7a, '[' }, /* Ground Digital (chideji) */ + { 0x7b, ']' }, /* Ground Analog (chiana) */ + + { 0xd0, '\"' }, /* Settings Menu (settei menu) */ + { 0x6d, '.' }, /* Radio/Data (rajio/data) */ + { 0x60, ',' }, /* CH 10-key input (search) */ + { 0x52, ':' }, /* subtitle (jimaku) */ + { 0x50, ';' }, /* hold (seishi) */ + + { 0x3a, 'A' }, /* Input- (nyuuryokukirikae-) */ + { 0x0f, 'B' }, /* Input+ (nyuuryokukirikae+) */ + { 0x29, 'C' }, /* Two screens (nigamen) */ + { 0x25, 'D' }, /* Broadband */ + { 0x27, 'E' }, /* |<< Skip backward */ + { 0x26, 'F' }, /* >>| Skip forward */ + { 0x61, '!' }, /* 1 NHK1 */ + { 0x62, '@' }, /* 2 NHK2 */ + { 0x63, '#' }, /* 3 NHKh */ + { 0x64, '$' }, /* 4 BS Nihon TV */ + { 0x65, '%' }, /* 5 BS Asahi */ + { 0x66, '^' }, /* 6 BS-i */ + { 0x67, '&' }, /* 7 BSJ */ + { 0x68, '*' }, /* 8 BS Fuji */ + { 0x69, '(' }, /* 9 WOW */ + { 0x6a, ')' }, /* 10 Star */ + { 0x6b, '-' }, /* 11 BS11 */ + { 0x6c, '+' }, /* 12 TwellV */ + { 0x27, '=' }, /* Quick (Delete) */ + { 0x34, '<' }, /* REGZA link */ + { 0x6e, '>' }, /* Program Table */ + { 0x20, '/' }, /* ^^ */ + { 0x22, '\'' }, /* << */ + { 0x23, '?' }, /* >> */ + { 0x21, '_' }, /* vv */ + + {0, 0} /* <> */ +}; + +static const struct codetable +cir_codetable_bravia[] = { + { 0x15, ' ' }, /* Power */ + { 0x95, '0' }, /* d (16-bit: 0x4b) */ + { 0x00, '1' }, /* 1 */ + { 0x01, '2' }, /* 2 */ + { 0x02, '3' }, /* 3 */ + { 0x03, '4' }, /* 4 */ + { 0x04, '5' }, /* 5 */ + { 0x05, '6' }, /* 6 */ + { 0x06, '7' }, /* 7 */ + { 0x07, '8' }, /* 8 */ + { 0x08, '9' }, /* 9 */ + { 0x09, 'a' }, /* 10 */ + { 0x0a, 'b' }, /* 11 */ + { 0x0b, 'c' }, /* 12 */ + { 0x10, 'd' }, /* CH+ */ + { 0x11, 'd' }, /* CH- */ + { 0x12, 'f' }, /* Vol+ */ + { 0x13, 'g' }, /* Vol- */ + { 0x14, 'h' }, /* Mute */ + { 0xa4, 'i' }, /* BLUE (16-bit: 0x4b) */ + { 0xa5, 'j' }, /* RED (16-bit: 0x4b) */ + { 0xa6, 'k' }, /* GREEN (16-bit: 0x4b) */ + { 0xa7, 'l' }, /* YELLOW (16-bit: 0x4b) */ + { 0x3a, 'm' }, /* DISPLAY control (gamen hyouji) */ + { 0x3d, 'n' }, /* Display Wide (waido kirikae) */ + { 0x74, 'o' }, /* UP */ + { 0x75, 'p' }, /* DOWN */ + { 0x33, 'q' }, /* RIGHT */ + { 0x34, 'r' }, /* LEFT */ + { 0x65, CH_RETURN }, /* Commit (kettei) */ + { 0xa3, CH_BACKSPACE }, /* Back (modoru) (16-bit: 0x4b) */ + { 0xac, 's' }, /* BS (16-bit: 0x4b) */ + { 0xab, 't' }, /* CS (16-bit: 0x4b) */ + { 0x5b, 'u' }, /* Program table (bangumi hyou) (16-bit: 0x52) */ + { 0x17, 'v' }, /* Sound channel (onsei kirikae) */ + { 0xa8, 'w' }, /* subtitle (jimaku) (16-bit: 0x4b) */ + { 0x5c, 'x' }, /* hold (memo) */ + { 0xb6, 'y' }, /* Tool (16-bit: 0x4b) */ + { 0x8c, 'z' }, /* 10 key input (10ki-) (16-bit: 0x4b) */ + { 0x60, '!' }, /* Menu */ + { 0xae, '@' }, /* Analog (16-bit: 0x4b) */ + { 0xb2, '#' }, /* Digital (16-bit: 0x4b) */ + { 0x25, '$' }, /* Input (nyuuryoku kirikae) */ + + {0, 0} /* <> */, +}; + +static int +ch_is_backspace (int ch) +{ + return ch == CH_BACKSPACE; +} + +static int +ch_is_enter (int ch) +{ + return ch == CH_RETURN; +} + +/* liner search is good enough for this small amount of data */ +static uint8_t +find_char_codetable (uint32_t cir_code, const struct codetable *ctp) +{ + while (ctp->cir_code != 0x0000 || ctp->char_code != 0x00) + if (ctp->cir_code == cir_code) + return ctp->char_code; + else + ctp++; + + /* Not found */ + return cir_code & 0xff; +} + +static int +hex (int x) +{ + if (x < 10) + return x + '0'; + else + return (x - 10) + 'a'; +} + +static int +cir_getchar (systime_t timeout) +{ + uint16_t cir_addr; + eventmask_t m; +#if defined(DEBUG_CIR) + uint16_t *p; +#endif + +#if defined(DEBUG_CIR) + cirinput_p = cirinput; +#endif + + chEvtClear (ALL_EVENTS); + cir_init (); + + m = chEvtWaitOneTimeout (ALL_EVENTS, timeout); + if (m == 0) + return -1; + +#if defined(DEBUG_CIR) + DEBUG_INFO ("****\r\n"); + DEBUG_SHORT (intr_ext); + DEBUG_SHORT (intr_trg); + DEBUG_SHORT (intr_ovf); + DEBUG_INFO ("----\r\n"); + for (p = cirinput; p < cirinput_p; p++) + DEBUG_SHORT (*p); + DEBUG_INFO ("====\r\n"); + + cirinput_p = cirinput; + + DEBUG_INFO ("**** CIR data:"); + DEBUG_WORD (cir_data); + if (cir_seq > 48) + DEBUG_SHORT (cir_data_more); + DEBUG_BYTE (cir_seq); +#endif + + switch (cir_proto) + { + case CIR_PROTO_RC5: + cir_data &= 0x003f; + goto err; + case CIR_PROTO_RC6: + cir_addr = cir_data >> 8; /* in case of cir_seq == 16. 32??? */ + cir_data &= 0x00ff; + return find_char_codetable (cir_data, cir_codetable_dell_mr425); + case CIR_PROTO_NEC: + cir_addr = cir_data&0xffff; + if (cir_addr == CIR_ADDR_TOSHIBA_REGZA) + { + cir_data = (cir_data >> 16) & 0x00ff; + return find_char_codetable (cir_data, cir_codetable_regza); + } + else + goto err; + case CIR_PROTO_SHARP: + cir_addr = cir_data&0x0fff; + if (cir_addr == CIR_ADDR_SHARP_AQUOS) + { + cir_data = (cir_data>>16)&0x0fff; + return find_char_codetable (cir_data, cir_codetable_aquos); + } + else + goto err; + case CIR_PROTO_SONY: + /* Remove ADDRESS bits and filter COMMAND bits */ + if (cir_seq == 1 + 12) + { + cir_addr = cir_data >> 7; + cir_data = cir_data & 0x007f; + /* ADDRESS = 0x01 (5-bit) */ + } + else + { + cir_addr = cir_data >> 8; + cir_data = cir_data & 0x00ff; + /* ADDRESS = 0x4b or 0x52 (7-bit) */ + } + return find_char_codetable (cir_data, cir_codetable_bravia); + err: + default: + /* encode debug information */ + pin_input_len = 16; + pin_input_buffer[0] = hex (cir_proto >> 4); + pin_input_buffer[1] = hex (cir_proto & 0x0f); + pin_input_buffer[2] = ':'; + pin_input_buffer[3] = hex ((cir_data >> 28) & 0x0f); + pin_input_buffer[4] = hex ((cir_data >> 24) & 0x0f); + pin_input_buffer[5] = hex ((cir_data >> 20) & 0x0f); + pin_input_buffer[6] = hex ((cir_data >> 16) & 0x0f); + pin_input_buffer[7] = hex ((cir_data >> 12) & 0x0f); + pin_input_buffer[8] = hex ((cir_data >> 8) & 0x0f); + pin_input_buffer[9] = hex ((cir_data >> 4) & 0x0f); + pin_input_buffer[10] = hex (cir_data & 0x0f); + pin_input_buffer[11] = ':'; + pin_input_buffer[12] = hex ((cir_data_more >> 12) & 0x0f); + pin_input_buffer[13] = hex ((cir_data_more >> 8) & 0x0f); + pin_input_buffer[14] = hex ((cir_data_more >> 4) & 0x0f); + pin_input_buffer[15] = hex (cir_data_more & 0x0f); + return CH_RETURN; + } +} + /* * RC-5 protocol doesn't have a start bit, while any other protocols * have the one. @@ -207,125 +593,56 @@ static systime_t cir_input_last; #define CIR_BIT_PERIOD 1500 #define CIR_BIT_SIRC_PERIOD_ON 1000 -static void -cir_init (void) -{ - cir_data = 0; - cir_seq = 0; - /* Don't touch cir_proto here */ - cir_ext_enable (); -} - static Thread *pin_thread; -static int -cir_key_is_backspace (void) +/* + * Let user input PIN string. + * Return length of the string. + * The string itself is in PIN_INPUT_BUFFER. + */ +int +pinpad_getline (int msg_code, systime_t timeout) { - return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_BACKSPACE) - || (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_BACKSPACE) - || (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_BACKSPACE) - || (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_BACKSPACE); -} - -static int -cir_key_is_enter (void) -{ - return (cir_proto == CIR_PROTO_RC6 && cir_data == CIR_KEY_RC6_ENTER) - || (cir_proto == CIR_PROTO_NEC && cir_data == CIR_KEY_NEC_ENTER) - || (cir_proto == CIR_PROTO_SONY && cir_data == CIR_KEY_SONY_ENTER) - || (cir_proto == CIR_PROTO_SHARP && cir_data == CIR_KEY_SHARP_ENTER); -} - -msg_t -pin_main (void *arg) -{ - uint8_t s = 0; - int msg_code = (int)arg; - (void)msg_code; + pin_thread = chThdSelf (); -#if defined(DEBUG_CIR) - cirinput_p = cirinput; -#endif + DEBUG_INFO (">>>\r\n"); pin_input_len = 0; - chEvtClear (ALL_EVENTS); - cir_init (); - - while (!chThdShouldTerminate ()) + while (1) { - eventmask_t m; + int ch; - m = chEvtWaitOneTimeout (ALL_EVENTS, PINDISP_TIMEOUT_INTERVAL1); + ch = cir_getchar (timeout); + if (ch < 0) + return 0; /* timeout */ - if (m) + if (ch_is_backspace (ch)) { -#if defined(DEBUG_CIR) - uint16_t *p; - - DEBUG_INFO ("****\r\n"); - DEBUG_SHORT (intr_ext); - DEBUG_SHORT (intr_trg); - DEBUG_SHORT (intr_ovf); - DEBUG_INFO ("----\r\n"); - for (p = cirinput; p < cirinput_p; p++) - DEBUG_SHORT (*p); - DEBUG_INFO ("====\r\n"); - - cirinput_p = cirinput; -#endif - DEBUG_INFO ("**** CIR data:"); - DEBUG_WORD (cir_data); - if (cir_seq > 48) - { - DEBUG_SHORT (cir_data_more); - } - DEBUG_BYTE (cir_seq); - - if (cir_key_is_backspace ()) - { - if (pin_input_len > 0) - pin_input_len--; - } - else if (cir_key_is_enter ()) - { - pindisp (' '); - chThdExit (0); - } - else if (pin_input_len < MAX_PIN_CHARS) - pin_input_buffer[pin_input_len++] = (uint8_t)cir_data; - - cir_init (); + led_blink (LED_TWOSHOTS); + if (pin_input_len > 0) + pin_input_len--; } - - switch (s++) + else if (ch_is_enter (ch)) + break; + else if (pin_input_len < MAX_PIN_CHARS) { - case 0: - pindisp ('G'); - break; - case 1: - pindisp ('P'); - break; - case 2: - pindisp ('G'); - break; - case 3: - pindisp ('.'); - break; - default: - pindisp (' '); - s = 0; - break; + led_blink (LED_ONESHOT); + pin_input_buffer[pin_input_len++] = ch; } - - chThdSleep (PINDISP_TIMEOUT_INTERVAL0); } cir_ext_disable (); - return 0; + + return pin_input_len; } +/** + * @brief Interrupt handler of EXTI. + * @note This handler will be invoked at the beginning of signal. + * Setup timer to measure period and duty using PWM input mode. + */ void cir_ext_interrupt (void) { @@ -340,29 +657,33 @@ cir_ext_interrupt (void) } #endif - TIM3->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */ + TIMx->EGR = TIM_EGR_UG; /* Generate UEV to load PSC and ARR */ /* Enable Timer */ - TIM3->SR &= ~(TIM_SR_UIF + TIMx->SR &= ~(TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_TIF | TIM_SR_CC1OF | TIM_SR_CC2OF); - TIM3->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/; - TIM3->CR1 |= TIM_CR1_CEN; + TIMx->DIER = TIM_DIER_UIE /*overflow*/ | TIM_DIER_TIE /*trigger*/; + TIMx->CR1 |= TIM_CR1_CEN; } #define CIR_PERIOD_ON_RC5_OR_RC6 (((cir_proto == CIR_PROTO_RC5) ? 2 : 1) \ * CIR_BIT_PERIOD_RC6 * 3 / 2) +/** + * @brief Interrupt handler of timer. + * @note Timer is PWM input mode, this handler will be invoked on each cycle + */ void cir_timer_interrupt (void) { uint16_t period, on, off; - period = TIM3->CCR1; - on = TIM3->CCR2; + period = TIMx->CCR1; + on = TIMx->CCR2; off = period - on; - if ((TIM3->SR & TIM_SR_TIF)) + if ((TIMx->SR & TIM_SR_TIF)) { if (cir_seq == 0) { @@ -477,23 +798,23 @@ cir_timer_interrupt (void) intr_trg++; #endif - TIM3->EGR = TIM_EGR_UG; /* Generate UEV */ - TIM3->SR &= ~TIM_SR_TIF; + TIMx->EGR = TIM_EGR_UG; /* Generate UEV */ + TIMx->SR &= ~TIM_SR_TIF; } else /* overflow occurred */ { systime_t now = chTimeNow (); - TIM3->SR &= ~TIM_SR_UIF; + TIMx->SR &= ~TIM_SR_UIF; if (on > 0) { uint8_t ignore_input = 0; /* Disable the timer */ - TIM3->CR1 &= ~TIM_CR1_CEN; - TIM3->DIER = 0; + TIMx->CR1 &= ~TIM_CR1_CEN; + TIMx->DIER = 0; if (cir_seq == 12 || cir_seq == 15) { @@ -536,14 +857,9 @@ cir_timer_interrupt (void) cir_input_last = now; ignore_input = 1; } - /* Remove ADDRESS bits and filter COMMAND bits */ else if (cir_proto == CIR_PROTO_SONY) { - if (cir_seq == 1 + 12) - cir_data = cir_data & 0x007f; - else if (cir_seq == 1 + 15) - cir_data = cir_data & 0x00ff; - else + if (cir_seq != 1 + 12 && cir_seq != 1 + 15) ignore_input = 1; } else if (cir_proto == CIR_PROTO_OTHER) @@ -551,10 +867,7 @@ cir_timer_interrupt (void) if (cir_seq == 1 + 32) { if (((cir_data >> 16) & 0xff) == ((cir_data >> 24) ^ 0xff)) - { - cir_proto = CIR_PROTO_NEC; - cir_data = (cir_data >> 16) & 0x00ff; - } + cir_proto = CIR_PROTO_NEC; else ignore_input = 1; } @@ -569,10 +882,7 @@ cir_timer_interrupt (void) ^ ((cir_data >> 20) & 0x0f) ^ ((cir_data >> 16) & 0x0f) ^ ((cir_data >> 12) & 0x0f) ^ ((cir_data >> 8) & 0x0f) ^ ((cir_data >> 4) & 0x0f) ^ (cir_data & 0x0f))) - { - cir_proto = CIR_PROTO_SHARP; - cir_data = (cir_data >> 16) & 0x0fff; - } + cir_proto = CIR_PROTO_SHARP; else ignore_input = 1; } @@ -581,16 +891,12 @@ cir_timer_interrupt (void) } else if (cir_proto == CIR_PROTO_RC6) { - if (cir_seq == 16 || cir_seq == 32) - cir_data &= 0x00ff; - else + if (cir_seq != 16 && cir_seq != 32) ignore_input = 1; } else if (cir_proto == CIR_PROTO_RC5) { - if (cir_seq == 14) - cir_data &= 0x003f; - else + if (cir_seq != 14) ignore_input = 1; } else @@ -603,7 +909,8 @@ cir_timer_interrupt (void) { cir_input_last = now; /* Notify thread */ - chEvtSignal (pin_thread, (eventmask_t)1); + if (pin_thread) + chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE); } #if defined(DEBUG_CIR) diff --git a/src/pin-dial.c b/src/pin-dial.c index d18ff65..d1e49d5 100644 --- a/src/pin-dial.c +++ b/src/pin-dial.c @@ -51,7 +51,7 @@ uint8_t pin_input_len; #define OFF '\x00' #define ENTER '\x0a' -static struct led_pattern { uint8_t c, v; } led_pattern[] = +static struct led_pattern { uint8_t c, v; } led_pattern[] = { /* char : dp a b c d e f g */ { ENTER, 0xf8 }, /* |- : 1 1 1 1 1 0 0 0 (enter) */ @@ -117,21 +117,19 @@ blink_dp (void) } static Thread *pin_thread; -#define EV_SW_PUSH (eventmask_t)1 void dial_sw_interrupt (void) { dial_sw_disable (); - chEvtSignalI (pin_thread, EV_SW_PUSH); + chEvtSignalI (pin_thread, EV_PINPAD_INPUT_DONE); palClearPad (IOPORT1, GPIOA_LED2); } -msg_t -pin_main (void *arg) +int +pinpad_getline (int msg_code, systime_t timeout) { - int msg_code = (int)arg; uint16_t count, count_prev; uint8_t input_mode; uint8_t sw_push_count; @@ -150,7 +148,7 @@ pin_main (void *arg) sw_push_count = 0; sw_event = 0; - while (!chThdShouldTerminate ()) + while (1) { eventmask_t m; @@ -158,7 +156,7 @@ pin_main (void *arg) dial_sw_enable (); m = chEvtWaitOneTimeout (ALL_EVENTS, LED_DISP_BLINK_INTERVAL0); - if (m == EV_SW_PUSH || sw_push_count) + if (m == EV_PINPAD_INPUT_DONE || sw_push_count) { if (palReadPad (IOPORT2, GPIOB_BUTTON) == 0) sw_push_count++; @@ -218,5 +216,5 @@ pin_main (void *arg) led_disp (OFF); TIM4->CR1 &= ~TIM_CR1_CEN; dial_sw_disable (); - return 0; + return pin_input_len; } diff --git a/src/pin-dnd.c b/src/pin-dnd.c new file mode 100644 index 0000000..aa1e1e4 --- /dev/null +++ b/src/pin-dnd.c @@ -0,0 +1,372 @@ +/* + * pin-dnd.c -- PIN input support (Drag and Drop with File Manager) + * + * Copyright (C) 2011 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 . + * + */ + +#include "config.h" +#include "ch.h" +#include "board.h" +#include "gnuk.h" +#include "usb-msc.h" + +struct folder { + uint8_t parent; + uint8_t children[7]; +}; + +static struct folder folders[8]; +static const struct folder folder_ini = { 0, { 1, 2, 3, 4, 5, 6, 7 } }; + + +uint8_t pin_input_buffer[MAX_PIN_CHARS]; +uint8_t pin_input_len; + +static Thread *pin_thread; + +/* + * Let user input PIN string. + * Return length of the string. + * The string itself is in PIN_INPUT_BUFFER. + */ +int +pinpad_getline (int msg_code, systime_t timeout) +{ + msg_t msg; + + (void)msg_code; + (void)timeout; + + DEBUG_INFO (">>>\r\n"); + + pin_input_len = 0; + + msc_media_insert_change (1); + + memset (folders, 0, sizeof folders); + memcpy (folders, &folder_ini, sizeof folder_ini); + + while (1) + { + chSysLock (); + pin_thread = chThdSelf (); + chSchGoSleepS (THD_STATE_SUSPENDED); + msg = chThdSelf ()->p_u.rdymsg; + chSysUnlock (); + + led_blink (LED_ONESHOT); + if (msg != 0) + break; + } + + msc_media_insert_change (0); + + if (msg == 1) + return pin_input_len; + else + return -1; /* cancel */ +} + +static void pinpad_input (void) +{ + chSysLock (); + pin_thread->p_u.rdymsg = 0; + chSchReadyI (pin_thread); + chSysUnlock (); +} + +static void pinpad_finish_entry (int cancel) +{ + chSysLock (); + if (cancel) + pin_thread->p_u.rdymsg = 2; + else + pin_thread->p_u.rdymsg = 1; + chSchReadyI (pin_thread); + chSysUnlock (); +} + +#define TOTAL_SECTOR 68 + +/* + +blk=0: master boot record sector +blk=1: fat0 +blk=2: fat1 +blk=3: root directory +blk=4: fat cluster #2 +... +blk=4+63: fat cluster #2+63 +*/ + +static const uint8_t d0_0_sector[] = { + 0xeb, 0x3c, /* Jump instruction */ + 0x90, /* NOP */ + + 0x6d, 0x6b, 0x64, 0x6f, 0x73, 0x66, 0x73, 0x20, /* "mkdosfs " */ + + 0x00, 0x02, /* Bytes per sector: 512 */ + + 0x01, /* sectors per cluster: 1 */ + 0x01, 0x00, /* reserved sector count: 1 */ + 0x02, /* Number of FATs: 2 */ + 0x10, 0x00, /* Max. root directory entries: 16 (1 sector) */ + TOTAL_SECTOR, 0x00, /* total sectors: 68 */ + 0xf8, /* media descriptor: fixed disk */ + 0x01, 0x00, /* sectors per FAT: 1 */ + 0x04, 0x00, /* sectors per track: 4 */ + 0x01, 0x00, /* number of heads: 1 */ + 0x00, 0x00, 0x00, 0x00, /* hidden sectors: 0 */ + 0x00, 0x00, 0x00, 0x00, /* total sectors (long) */ + 0x00, /* drive number */ + 0x00, /* reserved */ + 0x29, /* extended boot signature */ + 0xbf, 0x86, 0x75, 0xea, /* Volume ID (serial number) (Little endian) */ + + /* Volume label: DNDpinentry */ + 'D', 'n', 'D', 'p', 'i', 'n', 'e', 'n', 't', 'r', 'y', + + 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, /* FAT12 */ + + 0x0e, /* push cs */ + 0x1f, /* pop ds */ + 0xbe, 0x5b, 0x7c, /* mov si, offset message_txt */ + 0xac, /* 1: lodsb */ + 0x22, 0xc0, /* and al, al */ + 0x74, 0x0b, /* jz 2f */ + 0x56, /* push si */ + 0xb4, 0x0e, /* mov ah, 0eh */ + 0xbb, 0x07, 0x00, /* mov bx, 0007h */ + 0xcd, 0x10, /* int 10h ; output char color=white */ + 0x5e, /* pop si */ + 0xeb, 0xf0, /* jmp 1b */ + 0x32, 0xe4, /* 2: xor ah, ah */ + 0xcd, 0x16, /* int 16h; key input */ + 0xcd, 0x19, /* int 19h; load OS */ + 0xeb, 0xfe, /* 3: jmp 3b */ + + /* "This is not a bootable disk... \r\n" */ + 0x54, 0x68, 0x69, 0x73, 0x20, + 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, + 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20, + 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, + 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, + 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79, + 0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20, + 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, + 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e, + 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00, +}; + +static const uint8_t d0_fat0_sector[] = { + 0xf8, 0xff, 0xff, /* Media descriptor: fixed disk */ /* EOC */ + 0xff, 0xff, 0xff, /* cluster 2: used */ /* cluster 3: used */ + 0xff, 0xff, 0xff, /* cluster 4: used */ /* cluster 5: used */ + 0xff, 0xff, 0xff, /* cluster 6: used */ /* cluster 7: used */ + 0xff, 0x0f, 0x00, /* cluster 8: used */ /* cluster 9: free */ +}; + +static uint8_t the_sector[512]; + +#define FOLDER_INDEX_TO_CLUSTER_NO(i) (i+1) +#define CLUSTER_NO_TO_FOLDER_INDEX(n) (n-1) +#define FOLDER_INDEX_TO_LBA(i) (i+3) +#define LBA_TO_FOLDER_INDEX(lba) (lba-3) +#define FOLDER_INDEX_TO_DIRCHAR(i) ('A'+i-1) +#define DIRCHAR_TO_FOLDER_INDEX(c) (c - 'A' + 1) + +static uint8_t *fill_file_entry (uint8_t *p, const uint8_t *filename, + uint16_t cluster_no) +{ + memcpy (p, filename, 8+3); + p += 11; + *p++ = 0x10; /* directory */ + *p++ = 0x00; /* reserved */ + memcpy (p, "\x64\x3b\xa7\x61\x3f", 5); /* create time */ + p += 5; + memcpy (p, "\x61\x3f", 2); /* last access */ + p += 2; + *p++ = 0x00; *p++ = 0x00; /* ea-index */ + memcpy (p, "\x3b\xa7\x61\x3f", 4); /* last modified */ + p += 4; + memcpy (p, &cluster_no, 2); /* cluster # */ + p += 2; + *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* file size */ + return p; +} + +static void build_directory_sector (uint8_t *p, uint8_t index) +{ + uint16_t cluster_no = FOLDER_INDEX_TO_CLUSTER_NO (index); + int i; + uint8_t filename[11] = { 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20 }; + uint8_t child; + + memset (p, 0, 512); + + if (index != 0) + { + p = fill_file_entry (p, filename, cluster_no); + filename[1] = 0x2e; + p = fill_file_entry (p, filename, 0); + filename[1] = 0x20; + } + + for (i = 0; i < 7; i++) + if ((child = folders[index].children[i]) != 0) + { + filename[0] = FOLDER_INDEX_TO_DIRCHAR (child); + p = fill_file_entry (p, filename, FOLDER_INDEX_TO_CLUSTER_NO (child)); + } + else + break; +} + +int +msc_scsi_read (uint32_t lba, const uint8_t **sector_p) +{ + if (!media_available) + return SCSI_ERROR_NOT_READY; + + if (lba >= TOTAL_SECTOR) + return SCSI_ERROR_ILLEAGAL_REQUEST; + + switch (lba) + { + case 0: + *sector_p = the_sector; + memcpy (the_sector, d0_0_sector, sizeof d0_0_sector); + memset (the_sector + sizeof d0_0_sector, 0, 512 - sizeof d0_0_sector); + the_sector[510] = 0x55; + the_sector[511] = 0xaa; + return 0; + case 1: + case 2: + *sector_p = the_sector; + memcpy (the_sector, d0_fat0_sector, sizeof d0_fat0_sector); + memset (the_sector + sizeof d0_fat0_sector, 0, + 512 - sizeof d0_fat0_sector); + return 0; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + *sector_p = the_sector; + build_directory_sector (the_sector, LBA_TO_FOLDER_INDEX (lba)); + return 0; + default: + *sector_p = the_sector; + memset (the_sector, 0, 512); + return 0; + } +} + + +static void parse_directory_sector (const uint8_t *p, uint8_t index) +{ + int i; + uint8_t child; + int input = 0; + int num_children = 0; + + if (index != 0) + { + uint16_t cluster_no; + uint8_t dest_index; + + p += 32; /* skip "." */ + + /* ".." */ + cluster_no = p[26] | (p[27] << 8); + dest_index = CLUSTER_NO_TO_FOLDER_INDEX (cluster_no); + + if (dest_index < 1 || dest_index > 7) + ; /* it can be 255 : root_dir */ + else + if (pin_input_len < MAX_PIN_CHARS - 2) + { + pin_input_buffer[pin_input_len++] + = FOLDER_INDEX_TO_DIRCHAR (index); + pin_input_buffer[pin_input_len++] + = FOLDER_INDEX_TO_DIRCHAR (dest_index); + input = 1; + } + + p += 32; + } + + for (i = 0; i < 7; i++) + { + if (*p >= 'A' && *p <= 'G') + { + child = DIRCHAR_TO_FOLDER_INDEX (*p); + folders[index].children[i] = child; + num_children++; + } + else + folders[index].children[i] = 0; + p += 32; + } + + if (index == 0 && num_children == 1) + pinpad_finish_entry (0); + else if (input) + pinpad_input (); +} + +int +msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size) +{ + (void)size; + + if (!media_available) + return SCSI_ERROR_NOT_READY; + + if (lba >= TOTAL_SECTOR) + return SCSI_ERROR_ILLEAGAL_REQUEST; + + if (lba == 1) + return 0; /* updating FAT, just ignore */ + + if (lba <= 2 || lba >= 11) + return SCSI_ERROR_DATA_PROTECT; + else + { + uint8_t index = LBA_TO_FOLDER_INDEX (lba); + + parse_directory_sector (buf, index); + return 0; + } +} + +void +msc_scsi_stop (uint8_t code) +{ + (void)code; + pinpad_finish_entry (1); +} diff --git a/src/random.c b/src/random.c index d099cf1..7f0b7bc 100644 --- a/src/random.c +++ b/src/random.c @@ -1,7 +1,7 @@ /* * random.c -- get random bytes * - * Copyright (C) 2010, 2011 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -59,6 +59,7 @@ void random_bytes_free (const uint8_t *p) { (void)p; + memset (random_word, 0, RANDOM_BYTES_LENGTH); neug_flush (); } @@ -70,3 +71,32 @@ get_salt (void) { return neug_get (NEUG_KICK_FILLING); } + + +#ifdef KEYGEN_SUPPORT +/* + * Random byte iterator + */ +uint8_t +random_byte (void *arg) +{ + uint8_t *index_p = (uint8_t *)arg; + uint8_t index = *index_p; + uint8_t *p = ((uint8_t *)random_word) + index; + uint8_t v; + + neug_wait_full (); + + v = *p; + + if (++index >= RANDOM_BYTES_LENGTH) + { + index = 0; + neug_flush (); + } + + *index_p = index; + + return v; +} +#endif diff --git a/src/sha256.c b/src/sha256.c new file mode 100644 index 0000000..0be2a1f --- /dev/null +++ b/src/sha256.c @@ -0,0 +1,221 @@ +/* + * sha256.c -- Compute SHA-256 hash + * + * Just for little endian architecture. + * + * Code taken from: + * http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php + * + * File names are sha2.c, sha2.h, brg_types.h, brg_endian.h + * in the archive sha2-07-01-07.zip. + * + * Code is modified in the style of PolarSSL API. + * + * See original copyright notice below. + */ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 01/08/2005 +*/ + +#include +#include +#include +#include "sha256.h" + +#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) + +static void bswap32_buf (uint32_t *p, int n) +{ + while (n--) + p[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */ +} + +#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) + +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) + +/* round transforms for SHA256 compression functions */ +#define vf(n,i) v[(n - i) & 7] + +#define hf(i) (p[i & 15] += \ + g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15])) + +#define v_cycle(i,j) \ + vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \ + + s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \ + vf(3,i) += vf(7,i); \ + vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i)) + +#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) +#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) +#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) +#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) +#define k_0 k256 + +const uint32_t k256[64] = { + 0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5, + 0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5, + 0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3, + 0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174, + 0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC, + 0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA, + 0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7, + 0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967, + 0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13, + 0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85, + 0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3, + 0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070, + 0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5, + 0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3, + 0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208, + 0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2, +}; + +void +sha256_process (sha256_context *ctx) +{ + uint32_t i; + uint32_t *p = ctx->wbuf; + uint32_t v[8]; + + memcpy (v, ctx->state, 8 * sizeof (uint32_t)); + + for (i = 0; i < 64; i += 16) + { + v_cycle ( 0, i); + v_cycle ( 1, i); + v_cycle ( 2, i); + v_cycle ( 3, i); + v_cycle ( 4, i); + v_cycle ( 5, i); + v_cycle ( 6, i); + v_cycle ( 7, i); + v_cycle ( 8, i); + v_cycle ( 9, i); + v_cycle (10, i); + v_cycle (11, i); + v_cycle (12, i); + v_cycle (13, i); + v_cycle (14, i); + v_cycle (15, i); + } + + ctx->state[0] += v[0]; + ctx->state[1] += v[1]; + ctx->state[2] += v[2]; + ctx->state[3] += v[3]; + ctx->state[4] += v[4]; + ctx->state[5] += v[5]; + ctx->state[6] += v[6]; + ctx->state[7] += v[7]; +} + +void +sha256_update (sha256_context *ctx, const unsigned char *input, + unsigned int ilen) +{ + uint32_t left = (ctx->total[0] & SHA256_MASK); + uint32_t fill = SHA256_BLOCK_SIZE - left; + + ctx->total[0] += ilen; + if (ctx->total[0] < ilen) + ctx->total[1]++; + + while (ilen >= fill) + { + memcpy (((unsigned char*)ctx->wbuf) + left, input, fill); + bswap32_buf (ctx->wbuf, SHA256_BLOCK_SIZE >> 2); + sha256_process (ctx); + input += fill; + ilen -= fill; + left = 0; + fill = SHA256_BLOCK_SIZE; + } + + memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen); +} + +void +sha256_finish (sha256_context *ctx, unsigned char output[32]) +{ + uint32_t last = (ctx->total[0] & SHA256_MASK); + + bswap32_buf (ctx->wbuf, (last + 3) >> 2); + + ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3)); + ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3)); + + if (last > SHA256_BLOCK_SIZE - 9) + { + if (last < 60) + ctx->wbuf[15] = 0; + sha256_process (ctx); + last = 0; + } + else + last = (last >> 2) + 1; + + while (last < 14) + ctx->wbuf[last++] = 0; + + ctx->wbuf[14] = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + ctx->wbuf[15] = ctx->total[0] << 3; + sha256_process (ctx); + + bswap32_buf (ctx->state, SHA256_DIGEST_SIZE >> 2); + memcpy (output, ctx->state, SHA256_DIGEST_SIZE); + memset (ctx, 0, sizeof (sha256_context)); +} + +const uint32_t initial_state[8] = +{ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +void +sha256_start (sha256_context *ctx) +{ + ctx->total[0] = ctx->total[1] = 0; + memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t)); +} + +void +sha256 (const unsigned char *input, unsigned int ilen, + unsigned char output[32]) +{ + sha256_context ctx; + + sha256_start (&ctx); + sha256_update (&ctx, input, ilen); + sha256_finish (&ctx, output); +} diff --git a/src/sha256.h b/src/sha256.h new file mode 100644 index 0000000..5591eb2 --- /dev/null +++ b/src/sha256.h @@ -0,0 +1,17 @@ +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +typedef struct +{ + uint32_t total[2]; + uint32_t state[8]; + uint32_t wbuf[16]; +} sha256_context; + +extern void sha256 (const unsigned char *input, unsigned int ilen, + unsigned char output[32]); +extern void sha256_start (sha256_context *ctx); +extern void sha256_finish (sha256_context *ctx, unsigned char output[32]); +extern void sha256_update (sha256_context *ctx, const unsigned char *input, + unsigned int ilen); +extern void sha256_process (sha256_context *ctx); diff --git a/src/stmusb.mk b/src/stmusb.mk deleted file mode 100644 index 3d7c954..0000000 --- a/src/stmusb.mk +++ /dev/null @@ -1,7 +0,0 @@ -STMUSBDIR = ../STM32_USB-FS-Device_Driver -STMUSBSRCDIR = $(STMUSBDIR)/src -STMUSBINCDIR = $(STMUSBDIR)/inc -STMUSBSRC= $(STMUSBSRCDIR)/usb_sil.c \ - $(STMUSBSRCDIR)/usb_init.c $(STMUSBSRCDIR)/usb_int.c \ - $(STMUSBSRCDIR)/usb_mem.c $(STMUSBSRCDIR)/usb_core.c \ - $(STMUSBSRCDIR)/usb_regs.c diff --git a/src/sys.c b/src/sys.c new file mode 100644 index 0000000..7e70df1 --- /dev/null +++ b/src/sys.c @@ -0,0 +1,307 @@ +/* + * sys.c - system services at the first flash ROM blocks + * + * Copyright (C) 2012 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 . + * + */ + +#include "config.h" +#include "ch.h" +#include "hal.h" +#include "board.h" +#include "usb_lld.h" + +extern uint8_t __flash_start__, __flash_end__; + + +static void +usb_cable_config (int enable) +{ +#if defined(SET_USB_CONDITION) + if (SET_USB_CONDITION (enable)) + palSetPad (IOPORT_USB, GPIO_USB); + else + palClearPad (IOPORT_USB, GPIO_USB); +#else + (void)enable; +#endif +} + +static void +set_led (int on) +{ + if (SET_LED_CONDITION (on)) + palSetPad (IOPORT_LED, GPIO_LED); + else + palClearPad (IOPORT_LED, GPIO_LED); +} + + +#define FLASH_KEY1 0x45670123UL +#define FLASH_KEY2 0xCDEF89ABUL + +static void +flash_unlock (void) +{ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; +} + + +static int +flash_wait_for_last_operation (uint32_t timeout) +{ + int status; + + do + { + status = FLASH->SR; + if (--timeout == 0) + break; + } + while ((status & FLASH_SR_BSY) != 0); + + return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR); +} + +#define FLASH_PROGRAM_TIMEOUT 0x00010000 +#define FLASH_ERASE_TIMEOUT 0x01000000 + +static int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + + port_disable (); + if (status == 0) + { + FLASH->CR |= FLASH_CR_PG; + + *(volatile uint16_t *)addr = data; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + FLASH->CR &= ~FLASH_CR_PG; + } + port_enable (); + + return status; +} + +static int +flash_erase_page (uint32_t addr) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + + port_disable (); + if (status == 0) + { + FLASH->CR |= FLASH_CR_PER; + FLASH->AR = addr; + FLASH->CR |= FLASH_CR_STRT; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + FLASH->CR &= ~FLASH_CR_PER; + } + port_enable (); + + return status; +} + +static int +flash_check_blank (const uint8_t *p_start, size_t size) +{ + const uint8_t *p; + + for (p = p_start; p < p_start + size; p++) + if (*p != 0xff) + return 0; + + return 1; +} + +static int +flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) +{ + int status; + uint32_t flash_start = (uint32_t)&__flash_start__; + uint32_t flash_end = (uint32_t)&__flash_end__; + + if (dst_addr < flash_start || dst_addr + len > flash_end) + return 0; + + while (len) + { + uint16_t hw = *src++; + + hw |= (*src++ << 8); + status = flash_program_halfword (dst_addr, hw); + if (status != 0) + return 0; /* error return */ + + dst_addr += 2; + len -= 2; + } + + return 1; +} + +#define OPTION_BYTES_ADDR 0x1ffff800 + +static int +flash_protect (void) +{ + int status; + uint32_t option_bytes_value; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + + port_disable (); + if (status == 0) + { + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + FLASH->CR |= FLASH_CR_OPTER; + FLASH->CR |= FLASH_CR_STRT; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + FLASH->CR &= ~FLASH_CR_OPTER; + } + port_enable (); + + if (status != 0) + return 0; + + option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR; + return (option_bytes_value & 0xff) == 0xff ? 1 : 0; +} + + +static void __attribute__((naked)) +flash_erase_all_and_exec (void (*entry)(void)) +{ + uint32_t addr = (uint32_t)&__flash_start__; + uint32_t end = (uint32_t)&__flash_end__; + int r; + + while (addr < end) + { + r = flash_erase_page (addr); + if (r != 0) + break; + + addr += FLASH_PAGE_SIZE; + } + + if (addr >= end) + (*entry) (); + + for (;;); +} + +static void +nvic_enable_vector (uint32_t n, uint32_t prio) +{ + unsigned int sh = (n & 3) << 3; + + NVIC_IPR (n >> 2) = (NVIC_IPR(n >> 2) & ~(0xFF << sh)) | (prio << sh); + NVIC_ICPR (n >> 5) = 1 << (n & 0x1F); + NVIC_ISER (n >> 5) = 1 << (n & 0x1F); +} + +static void +usb_lld_sys_init (void) +{ + RCC->APB1ENR |= RCC_APB1ENR_USBEN; + nvic_enable_vector (USB_LP_CAN1_RX0_IRQn, + CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY)); + /* + * Note that we also have other IRQ(s): + * USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous) + * USBWakeUp_IRQn (suspend/resume) + */ + RCC->APB1RSTR = RCC_APB1RSTR_USBRST; + RCC->APB1RSTR = 0; + + usb_cable_config (1); +} + +static void +usb_lld_sys_shutdown (void) +{ + RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; + usb_cable_config (0); +} + +#define SYSRESETREQ 0x04 +static void +nvic_system_reset (void) +{ + SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ); + asm volatile ("dsb"); +} + +static void __attribute__ ((naked)) +reset (void) +{ + asm volatile ("cpsid i\n\t" /* Mask all interrupts. */ + "mov.w r0, #0xed00\n\t" /* r0 = SCR */ + "movt r0, #0xe000\n\t" + "mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */ + "mov r2, #0x1000\n\t" + "add r1, r1, r2\n\t" + "sub r2, r2, #1\n\t" + "bic r1, r1, r2\n\t" + "str r1, [r0, #8]\n\t" /* Set SCR->VCR */ + "ldr r0, [r1], #4\n\t" + "msr MSP, r0\n\t" /* Main (exception handler) stack. */ + "ldr r0, [r1]\n\t" /* Reset handler. */ + "bx r0\n" + : /* no output */ : /* no input */ : "memory"); +} + +typedef void (*handler)(void); +extern uint8_t __ram_end__; + +handler vector[] __attribute__ ((section(".vectors"))) = { + (handler)&__ram_end__, + reset, + (handler)set_led, + flash_unlock, + (handler)flash_program_halfword, + (handler)flash_erase_page, + (handler)flash_check_blank, + (handler)flash_write, + (handler)flash_protect, + (handler)flash_erase_all_and_exec, + usb_lld_sys_init, + usb_lld_sys_shutdown, + nvic_system_reset, +}; + +const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = { + 3*2+2, /* bLength */ + 0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/ + /* sys version: "1.0" */ + '1', 0, '.', 0, '0', 0, +}; diff --git a/src/sys.h b/src/sys.h new file mode 100644 index 0000000..3884c95 --- /dev/null +++ b/src/sys.h @@ -0,0 +1,95 @@ +extern const uint8_t sys_version[8]; + +typedef void (*handler)(void); +extern handler vector[14]; + +static inline const uint8_t * +unique_device_id (void) +{ + /* STM32F103 has 96-bit unique device identifier */ + const uint8_t *addr = (const uint8_t *)0x1ffff7e8; + + return addr; +} + +static inline void +set_led (int on) +{ + void (*func) (int) = (void (*)(int))vector[2]; + + return (*func) (on); +} + +static inline void +flash_unlock (void) +{ + (*vector[3]) (); +} + +static inline int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4]; + + return (*func) (addr, data); +} + +static inline int +flash_erase_page (uint32_t addr) +{ + int (*func) (uint32_t) = (int (*)(uint32_t))vector[5]; + + return (*func) (addr); +} + +static inline int +flash_check_blank (const uint8_t *p_start, size_t size) +{ + int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6]; + + return (*func) (p_start, size); +} + +static inline int +flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) +{ + int (*func) (uint32_t, const uint8_t *, size_t) + = (int (*)(uint32_t, const uint8_t *, size_t))vector[7]; + + return (*func) (dst_addr, src, len); +} + +static inline int +flash_protect (void) +{ + int (*func) (void) = (int (*)(void))vector[8]; + + return (*func) (); +} + +static inline void __attribute__((noreturn)) +flash_erase_all_and_exec (void (*entry)(void)) +{ + void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9]; + + (*func) (entry); + for (;;); +} + +static inline void +usb_lld_sys_init (void) +{ + (*vector[10]) (); +} + +static inline void +usb_lld_sys_shutdown (void) +{ + (*vector[11]) (); +} + +static inline void +nvic_system_reset (void) +{ + (*vector[12]) (); +} diff --git a/src/usb-cdc-vport.c b/src/usb-cdc-vport.c deleted file mode 100644 index 23a1c81..0000000 --- a/src/usb-cdc-vport.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is included by usb_prop.c to provide Virtual COM port feature - */ - -/* Original is ../Virtual_COM_Port/usb_prop.c by STMicroelectronics */ -/* Chopped and modified for Gnuk */ - -#include "usb-cdc.h" - -/* Original copyright notice is following: */ -/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** -* File Name : usb_prop.c -* Author : MCD Application Team -* Version : V3.1.1 -* Date : 04/07/2010 -* Description : All processing related to Virtual Com Port Demo -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -*******************************************************************************/ - -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; -} - -static RESULT -Virtual_Com_Port_Data_Setup (uint8_t RequestNo) -{ - uint8_t *(*CopyRoutine)(uint16_t); - - CopyRoutine = NULL; - - if (RequestNo == USB_CDC_REQ_GET_LINE_CODING) - CopyRoutine = Virtual_Com_Port_GetLineCoding; - else if (RequestNo == USB_CDC_REQ_SET_LINE_CODING) - CopyRoutine = Virtual_Com_Port_SetLineCoding; - - if (CopyRoutine == NULL) - return USB_UNSUPPORT; - - pInformation->Ctrl_Info.CopyData = CopyRoutine; - pInformation->Ctrl_Info.Usb_wOffset = 0; - (*CopyRoutine) (0); /* Set Ctrl_Info.Usb_wLength */ - - return USB_SUCCESS; -} - -static RESULT -Virtual_Com_Port_NoData_Setup (uint8_t RequestNo) -{ - if (RequestNo == USB_CDC_REQ_SET_CONTROL_LINE_STATE) - /* Do nothing and success */ - return USB_SUCCESS; - - return USB_UNSUPPORT; -} diff --git a/src/usb-cdc.h b/src/usb-cdc.h index 93fcd4e..d004c79 100644 --- a/src/usb-cdc.h +++ b/src/usb-cdc.h @@ -5,3 +5,6 @@ #define USB_CDC_REQ_GET_LINE_CODING 0x21 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 #define USB_CDC_REQ_SEND_BREAK 0x23 + +#define VIRTUAL_COM_PORT_DATA_SIZE 16 +#define VIRTUAL_COM_PORT_INT_SIZE 8 diff --git a/src/usb-icc.c b/src/usb-icc.c index d526513..8cd0ebc 100644 --- a/src/usb-icc.c +++ b/src/usb-icc.c @@ -1,7 +1,7 @@ /* * usb-icc.c -- USB CCID/ICCD protocol handling * - * Copyright (C) 2010, 2011 Free Software Initiative of Japan + * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -25,11 +25,108 @@ #include "ch.h" #include "hal.h" #include "gnuk.h" -#include "usb_lib.h" -#include "usb_desc.h" -#include "usb_mem.h" -#include "hw_config.h" -#include "usb_istr.h" +#include "usb_lld.h" + +/* + * USB buffer size of USB-ICC driver + */ +#if MAX_RES_APDU_DATA_SIZE > MAX_CMD_APDU_DATA_SIZE +#define USB_BUF_SIZE (MAX_RES_APDU_DATA_SIZE+5) +#else +#define USB_BUF_SIZE (MAX_CMD_APDU_DATA_SIZE+5) +#endif + +struct apdu apdu; + +/* + * There are three layers in USB CCID implementation + * + * +-------------------+ + * | Application Layer | + * +-------------------+ + * ^ command APDU | + * | v response APDU + * +-------------------+ + * | CCID Layer | + * +-------------------+ + * ^ CCID PC_to_RDR | CCID RDR_to_PC + * | Message v Message + * +-------------------+ + * | USB Layer | + * +-------------------+ + * ^ USB | USB + * | Bulk-OUT Packet v Bulk-IN Packet + * + */ + +/* + * USB layer data structures + */ + +struct ep_in { + uint8_t ep_num; + uint8_t tx_done; + void (*notify) (struct ep_in *epi); + const uint8_t *buf; + size_t cnt; + size_t buf_len; + void *priv; + void (*next_buf) (struct ep_in *epi, size_t len); +}; + +static void epi_init (struct ep_in *epi, int ep_num, + void (*notify) (struct ep_in *epi), void *priv) +{ + epi->ep_num = ep_num; + epi->tx_done = 0; + epi->notify = notify; + epi->buf = NULL; + epi->cnt = 0; + epi->buf_len = 0; + epi->priv = priv; + epi->next_buf = NULL; +} + +struct ep_out { + uint8_t ep_num; + uint8_t err; + void (*notify) (struct ep_out *epo); + uint8_t *buf; + size_t cnt; + size_t buf_len; + void *priv; + void (*next_buf) (struct ep_out *epo, size_t len); + int (*end_rx) (struct ep_out *epo, size_t orig_len); +}; + +static struct ep_out endpoint_out; +static struct ep_in endpoint_in; + +static void epo_init (struct ep_out *epo, int ep_num, + void (*notify) (struct ep_out *epo), void *priv) +{ + epo->ep_num = ep_num; + epo->err = 0; + epo->notify = notify; + epo->buf = NULL; + epo->cnt = 0; + epo->buf_len = 0; + epo->priv = priv; + epo->next_buf = NULL; + epo->end_rx = NULL; +} + +/* + * CCID Layer + */ + +/* + * Buffer of USB communication: for both of RX and TX + * + * The buffer will be filled by multiple RX packets (Bulk-OUT) + * or will be used for multiple TX packets (Bulk-IN) + */ +static uint8_t icc_buffer[USB_BUF_SIZE]; #define ICC_SET_PARAMS 0x61 /* non-ICCD command */ #define ICC_POWER_ON 0x62 @@ -47,7 +144,7 @@ #define ICC_MSG_ERROR_OFFSET 8 #define ICC_MSG_CHAIN_OFFSET 9 #define ICC_MSG_DATA_OFFSET 10 /* == ICC_MSG_HEADER_SIZE */ -#define ICC_MAX_MSG_DATA_SIZE (USB_BUF_SIZE - ICC_MSG_HEADER_SIZE) +#define ICC_MAX_MSG_DATA_SIZE USB_BUF_SIZE #define ICC_STATUS_RUN 0x00 #define ICC_STATUS_PRESENT 0x01 @@ -63,166 +160,520 @@ * error with offset 0 means "command not supported". */ #define ICC_OFFSET_CMD_NOT_SUPPORTED 0 +#define ICC_OFFSET_DATA_LEN 1 #define ICC_OFFSET_PARAM 8 struct icc_header { uint8_t msg_type; - int32_t data_len; + uint32_t data_len; uint8_t slot; uint8_t seq; uint8_t rsvd; uint16_t param; } __attribute__((packed)); -int icc_data_size; + +enum icc_state *icc_state_p; + +/* Data structure handled by CCID layer */ +struct ccid { + enum icc_state icc_state; + uint8_t state; + uint8_t *p; + size_t len; + + uint8_t err; + + struct icc_header icc_header; + + uint8_t sw1sw2[2]; + uint8_t chained_cls_ins_p1_p2[4]; + + Thread *icc_thread; + Thread *application; + + /* lower layer */ + struct ep_out *epo; + struct ep_in *epi; + + /* upper layer */ + struct apdu *a; +}; /* - * USB-ICC communication could be considered "half duplex". + * APDU_STATE_WAIT_COMMAND +---------+ + * | | | | + * | v v | + * | APDU_STATE_COMMAND_CHAINING --+ + * | | + * v v + * APDU_STATE_COMMAND_RECEIVED + * | + * v + * =================== + * | Process COMMAND | + * =================== + * | + * v + * +-----+----------+ +---------+ + * | | | | + * v v v | + * APDU_STATE_RESULT <---- APDU_STATE_RESULT_GET_RESPONSE --+ + * | + * | + * v + * APDU_STATE_WAIT_COMMAND + */ + +#define APDU_STATE_WAIT_COMMAND 0 +#define APDU_STATE_COMMAND_CHAINING 1 +#define APDU_STATE_COMMAND_RECEIVED 2 +#define APDU_STATE_RESULT 3 +#define APDU_STATE_RESULT_GET_RESPONSE 4 + +static void ccid_reset (struct ccid *c) +{ + c->err = 0; + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + c->a->cmd_apdu_data_len = 0; + c->a->expected_res_size = 0; +} + +static void ccid_init (struct ccid *c, struct ep_in *epi, struct ep_out *epo, + struct apdu *a, Thread *t) +{ + icc_state_p = &c->icc_state; + + c->icc_state = ICC_STATE_START; + c->state = APDU_STATE_WAIT_COMMAND; + /* + * Note: a is not yet initialized yet, we can't use c->a->cmd_apdu_data here. + */ + c->p = &icc_buffer[5]; + c->len = MAX_CMD_APDU_DATA_SIZE; + c->err = 0; + memset (&c->icc_header, 0, sizeof (struct icc_header)); + c->sw1sw2[0] = 0x90; + c->sw1sw2[1] = 0x00; + c->icc_thread = t; + c->application = NULL; + c->epi = epi; + c->epo = epo; + c->a = a; +} + +/* + * Application layer + */ + +/* + * USB-CCID communication could be considered "half duplex". * * While the device is sending something, there is no possibility for * the device to receive anything. * * While the device is receiving something, there is no possibility * for the device to send anything. - * - * Thus, the buffer can be shared for RX and TX. - */ - -/* - * Buffer of USB communication: for both of RX and TX * - * The buffer will be filled by multiple RX transactions (Bulk-OUT) - * or will be used for multiple TX transactions (Bulk-IN) + * Thus, the buffer can be shared for RX and TX. + * + * Exception: When we support ABORT of CCID, it is possible to receive + * ABORT Class Specific Request to control pipe while we are + * receiving/sending something at OUT/IN endpoint. + * */ -uint8_t icc_buffer[USB_BUF_SIZE]; -uint8_t icc_seq; -/* - * Pointer to ICC_BUFFER - */ -static uint8_t *icc_next_p; +#define CMD_APDU_HEAD_SIZE 5 -/* - * Chain pointer: This implementation support two packets in chain (not more) - */ -static uint8_t *icc_chain_p; +static void apdu_init (struct apdu *a) +{ + a->seq = 0; /* will be set by lower layer */ + a->cmd_apdu_head = &icc_buffer[0]; + a->cmd_apdu_data = &icc_buffer[5]; + a->cmd_apdu_data_len = 0; /* will be set by lower layer */ + a->expected_res_size = 0; /* will be set by lower layer */ -/* - * Whole size of TX transfer (Bulk-IN transactions) - */ -static int icc_tx_size; - -static Thread *icc_thread; + a->sw = 0x9000; /* will be set by upper layer */ + a->res_apdu_data = &icc_buffer[5]; /* will be set by upper layer */ + a->res_apdu_data_len = 0; /* will be set by upper layer */ +} #define EV_RX_DATA_READY (eventmask_t)1 /* USB Rx data available */ /* EV_EXEC_FINISHED == 2 */ #define EV_TX_FINISHED (eventmask_t)4 /* USB Tx finished */ + +static void notify_tx (struct ep_in *epi) +{ + struct ccid *c = (struct ccid *)epi->priv; + + /* The sequence of Bulk-IN transactions finished */ + chEvtSignalI (c->icc_thread, EV_TX_FINISHED); +} + +static void no_buf (struct ep_in *epi, size_t len) +{ + (void)len; + epi->buf = NULL; + epi->cnt = 0; + epi->buf_len = 0; +} + +static void set_sw1sw2 (struct ep_in *epi) +{ + struct ccid *c = (struct ccid *)epi->priv; + + if (c->a->expected_res_size >= c->len) + { + c->sw1sw2[0] = 0x90; + c->sw1sw2[1] = 0x00; + } + else + { + c->sw1sw2[0] = 0x61; + if (c->len >= 256) + c->sw1sw2[1] = 0; + else + c->sw1sw2[1] = (uint8_t)c->len; + } +} + +static void get_sw1sw2 (struct ep_in *epi, size_t len) +{ + struct ccid *c = (struct ccid *)epi->priv; + + (void)len; + epi->buf = c->sw1sw2; + epi->cnt = 0; + epi->buf_len = 2; + epi->next_buf = no_buf; +} + + /* * Tx done callback */ void EP1_IN_Callback (void) { - if (icc_next_p == NULL) - /* The sequence of Bulk-IN transactions finished */ - chEvtSignalI (icc_thread, EV_TX_FINISHED); - else if (icc_next_p == &icc_buffer[icc_tx_size]) - /* It was multiple of USB_LL_BUF_SIZE */ - { - /* Send the last 0-DATA transcation of Bulk-IN in the transactions */ - icc_next_p = NULL; - USB_SIL_Write (EP1_IN, icc_buffer, 0); - SetEPTxValid (ENDP1); - } + struct ep_in *epi = &endpoint_in; + + if (epi->buf == NULL) + if (epi->tx_done) + epi->notify (epi); + else + { + epi->tx_done = 1; + usb_lld_tx_enable (epi->ep_num, 0); /* send ZLP */ + } else { - int tx_size = USB_LL_BUF_SIZE; - uint8_t *p = icc_next_p; + int tx_size = 0; + size_t remain = USB_LL_BUF_SIZE; + int offset = 0; - icc_next_p += USB_LL_BUF_SIZE; - if (icc_next_p > &icc_buffer[icc_tx_size]) - { - icc_next_p = NULL; - tx_size = &icc_buffer[icc_tx_size] - p; - } + while (epi->buf) + if (epi->buf_len < remain) + { + usb_lld_txcpy (epi->buf, epi->ep_num, offset, epi->buf_len); + offset += epi->buf_len; + remain -= epi->buf_len; + tx_size += epi->buf_len; + epi->next_buf (epi, remain); /* Update epi->buf, cnt, buf_len */ + } + else + { + usb_lld_txcpy (epi->buf, epi->ep_num, offset, remain); + epi->buf += remain; + epi->cnt += remain; + epi->buf_len -= remain; + tx_size += remain; + break; + } - USB_SIL_Write (EP1_IN, p, tx_size); - SetEPTxValid (ENDP1); + if (tx_size < USB_LL_BUF_SIZE) + epi->tx_done = 1; + usb_lld_tx_enable (epi->ep_num, tx_size); } } -static void -icc_prepare_receive (int chain) -{ - if (chain) - icc_next_p = icc_chain_p; - else - icc_next_p = icc_buffer; - SetEPRxValid (ENDP2); +static void notify_icc (struct ep_out *epo) +{ + struct ccid *c = (struct ccid *)epo->priv; + + c->err = epo->err; + chEvtSignalI (c->icc_thread, EV_RX_DATA_READY); +} + +static int end_icc_rx (struct ep_out *epo, size_t orig_len) +{ + (void)orig_len; + if (epo->cnt < sizeof (struct icc_header)) + /* short packet, just ignore */ + return 1; + + /* icc message with no abdata */ + return 0; +} + +static int end_abdata (struct ep_out *epo, size_t orig_len) +{ + struct ccid *c = (struct ccid *)epo->priv; + size_t len = epo->cnt; + + if (orig_len == USB_LL_BUF_SIZE && len < c->icc_header.data_len) + /* more packet comes */ + return 1; + + if (len != c->icc_header.data_len) + epo->err = 1; + + return 0; +} + +static int end_cmd_apdu_head (struct ep_out *epo, size_t orig_len) +{ + struct ccid *c = (struct ccid *)epo->priv; + + (void)orig_len; + + if (epo->cnt < 4 || epo->cnt != c->icc_header.data_len) + { + epo->err = 1; + return 0; + } + + if ((c->state == APDU_STATE_COMMAND_CHAINING) + && (c->chained_cls_ins_p1_p2[0] != (c->a->cmd_apdu_head[0] & ~0x10) + || c->chained_cls_ins_p1_p2[1] != c->a->cmd_apdu_head[1] + || c->chained_cls_ins_p1_p2[2] != c->a->cmd_apdu_head[2] + || c->chained_cls_ins_p1_p2[3] != c->a->cmd_apdu_head[3])) + /* + * Handling exceptional request. + * + * Host stops sending command APDU using command chaining, + * and start another command APDU. + * + * Discard old one, and start handling new one. + */ + { + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + } + + if (epo->cnt == 4) + { + /* No Lc and Le */ + c->a->cmd_apdu_data_len = 0; + c->a->expected_res_size = 0; + } + else if (epo->cnt == 5) + { + /* No Lc but Le */ + c->a->cmd_apdu_data_len = 0; + c->a->expected_res_size = c->a->cmd_apdu_head[4]; + if (c->a->expected_res_size == 0) + c->a->expected_res_size = 256; + c->a->cmd_apdu_head[4] = 0; + } + + return 0; +} + + +static int end_nomore_data (struct ep_out *epo, size_t orig_len) +{ + (void)epo; + if (orig_len == USB_LL_BUF_SIZE) + return 1; + else + return 0; +} + + +static int end_cmd_apdu_data (struct ep_out *epo, size_t orig_len) +{ + struct ccid *c = (struct ccid *)epo->priv; + size_t len = epo->cnt; + + if (orig_len == USB_LL_BUF_SIZE + && CMD_APDU_HEAD_SIZE + len < c->icc_header.data_len) + /* more packet comes */ + return 1; + + if (CMD_APDU_HEAD_SIZE + len != c->icc_header.data_len) + goto error; + + if (len == c->a->cmd_apdu_head[4]) + /* No Le field*/ + c->a->expected_res_size = 0; + else if (len == (size_t)c->a->cmd_apdu_head[4] + 1) + { + /* it has Le field*/ + c->a->expected_res_size = epo->buf[-1]; + len--; + } + else + { + error: + epo->err = 1; + return 0; + } + + c->a->cmd_apdu_data_len += len; + return 0; +} + + +static void nomore_data (struct ep_out *epo, size_t len) +{ + (void)len; + epo->err = 1; + epo->end_rx = end_nomore_data; + epo->buf = NULL; + epo->buf_len = 0; + epo->cnt = 0; + epo->next_buf = nomore_data; +} + +#define INS_GET_RESPONSE 0xc0 + +static void icc_cmd_apdu_data (struct ep_out *epo, size_t len) +{ + struct ccid *c = (struct ccid *)epo->priv; + + (void)len; + if (c->state == APDU_STATE_RESULT_GET_RESPONSE + && c->a->cmd_apdu_head[1] != INS_GET_RESPONSE) + { + /* + * Handling exceptional request. + * + * Host didn't finish receiving the whole response APDU by GET RESPONSE, + * but initiates another command. + */ + + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + } + else if (c->state == APDU_STATE_COMMAND_CHAINING) + { + if (c->chained_cls_ins_p1_p2[0] != (c->a->cmd_apdu_head[0] & ~0x10) + || c->chained_cls_ins_p1_p2[1] != c->a->cmd_apdu_head[1] + || c->chained_cls_ins_p1_p2[2] != c->a->cmd_apdu_head[2] + || c->chained_cls_ins_p1_p2[3] != c->a->cmd_apdu_head[3]) + /* + * Handling exceptional request. + * + * Host stops sending command APDU using command chaining, + * and start another command APDU. + * + * Discard old one, and start handling new one. + */ + { + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + c->a->cmd_apdu_data_len = 0; + } + } + + epo->end_rx = end_cmd_apdu_data; + epo->buf = c->p; + epo->buf_len = c->len; + epo->cnt = 0; + epo->next_buf = nomore_data; +} + +static void icc_abdata (struct ep_out *epo, size_t len) +{ + struct ccid *c = (struct ccid *)epo->priv; + + (void)len; + c->a->seq = c->icc_header.seq; + if (c->icc_header.msg_type == ICC_XFR_BLOCK) + { + c->a->seq = c->icc_header.seq; + epo->end_rx = end_cmd_apdu_head; + epo->buf = c->a->cmd_apdu_head; + epo->buf_len = 5; + epo->cnt = 0; + epo->next_buf = icc_cmd_apdu_data; + } + else + { + epo->end_rx = end_abdata; + epo->buf = c->p; + epo->buf_len = c->len; + epo->cnt = 0; + epo->next_buf = nomore_data; + } +} + + +static void +icc_prepare_receive (struct ccid *c) +{ + DEBUG_INFO ("Rx ready\r\n"); + + c->epo->err = 0; + c->epo->buf = (uint8_t *)&c->icc_header; + c->epo->buf_len = sizeof (struct icc_header); + c->epo->cnt = 0; + c->epo->next_buf = icc_abdata; + c->epo->end_rx = end_icc_rx; + usb_lld_rx_enable (c->epo->ep_num); } /* * Rx ready callback */ + void -EP2_OUT_Callback (void) +EP1_OUT_Callback (void) { - int len; + struct ep_out *epo = &endpoint_out; + size_t len = usb_lld_rx_data_len (epo->ep_num); + int offset = 0; + int cont; + size_t orig_len = len; - len = USB_SIL_Read (EP2_OUT, icc_next_p); + while (epo->err == 0) + if (len == 0) + break; + else if (len <= epo->buf_len) + { + usb_lld_rxcpy (epo->buf, epo->ep_num, offset, len); + epo->buf += len; + epo->cnt += len; + epo->buf_len -= len; + break; + } + else /* len > buf_len */ + { + usb_lld_rxcpy (epo->buf, epo->ep_num, offset, epo->buf_len); + len -= epo->buf_len; + offset += epo->buf_len; + epo->next_buf (epo, len); /* Update epo->buf, cnt, buf_len */ + } - if (len == USB_LL_BUF_SIZE) /* The sequence of transactions continues */ - { - icc_next_p += USB_LL_BUF_SIZE; - SetEPRxValid (ENDP2); - if ((icc_next_p - icc_buffer) >= USB_BUF_SIZE) - /* No room to receive any more */ - { - DEBUG_INFO ("ERR0F\r\n"); - icc_next_p -= USB_LL_BUF_SIZE; /* Just for not overrun the buffer */ - /* - * Receive until the end of the sequence - * (and discard the whole block) - */ - } - } - else /* Finished */ - { - struct icc_header *icc_header; - int data_len; + /* + * ORIG_LEN to distingush ZLP and the end of transaction + * (ORIG_LEN != USB_LL_BUF_SIZE) + */ + cont = epo->end_rx (epo, orig_len); - icc_next_p += len; - if (icc_chain_p) - { - icc_header = (struct icc_header *)icc_chain_p; - icc_data_size = (icc_next_p - icc_chain_p) - ICC_MSG_HEADER_SIZE; - } - else - { - icc_header = (struct icc_header *)icc_buffer; - icc_data_size = (icc_next_p - icc_buffer) - ICC_MSG_HEADER_SIZE; - } - - /* NOTE: We're little endian, nothing to convert */ - data_len = icc_header->data_len; - icc_seq = icc_header->seq; - - if (icc_data_size != data_len) - { - DEBUG_INFO ("ERR0E\r\n"); - /* Ignore the whole block */ - icc_chain_p = NULL; - icc_prepare_receive (0); - } - else - /* Notify myself */ - chEvtSignalI (icc_thread, EV_RX_DATA_READY); - } + if (cont) + usb_lld_rx_enable (epo->ep_num); + else + epo->notify (epo); } -volatile enum icc_state icc_state; /* * ATR (Answer To Reset) string @@ -243,32 +694,26 @@ volatile enum icc_state icc_state; * Minimum: 0x3b, 0x8a, 0x80, 0x01, + historical bytes, xor check * */ -static const char ATR[] = { +static const uint8_t ATR[] = { 0x3b, 0xda, 0x11, 0xff, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0x03, 0x00, 0x31, 0x84, /* full DF name, GET DATA, MF */ 0x73, - 0x80, /* DF full name */ - 0x01, /* 1-byte */ - 0x40, /* Extended Lc and extended Le */ + 0x80, /* DF full name */ + 0x01, /* 1-byte */ + 0x80, /* Command chaining, No extended Lc and extended Le */ 0x00, 0x90, 0x00, (0xda^0x11^0xff^0x81^0xb1^0xfe^0x55^0x1f^0x03 - ^0x00^0x31^0x84^0x73^0x80^0x01^0x40^0x00^0x90^0x00) + ^0x00^0x31^0x84^0x73^0x80^0x01^0x80^0x00^0x90^0x00) }; /* * Send back error */ -void -icc_error (int offset) +static void icc_error (struct ccid *c, int offset) { - uint8_t *icc_reply; - - if (icc_chain_p) - icc_reply = icc_chain_p; - else - icc_reply = icc_buffer; + uint8_t icc_reply[ICC_MSG_HEADER_SIZE]; icc_reply[0] = ICC_SLOT_STATUS_RET; /* Any value should be OK */ icc_reply[1] = 0x00; @@ -276,8 +721,8 @@ icc_error (int offset) icc_reply[3] = 0x00; icc_reply[4] = 0x00; icc_reply[5] = 0x00; /* Slot */ - icc_reply[ICC_MSG_SEQ_OFFSET] = icc_seq; - if (icc_state == ICC_STATE_START) + icc_reply[ICC_MSG_SEQ_OFFSET] = c->icc_header.seq; + if (c->icc_state == ICC_STATE_START) /* 1: ICC present but not activated 2: No ICC present */ icc_reply[ICC_MSG_STATUS_OFFSET] = 1; else @@ -287,58 +732,55 @@ icc_error (int offset) icc_reply[ICC_MSG_ERROR_OFFSET] = offset; icc_reply[ICC_MSG_CHAIN_OFFSET] = 0x00; - icc_next_p = NULL; /* This is a single transaction Bulk-IN */ - icc_tx_size = ICC_MSG_HEADER_SIZE; - USB_SIL_Write (EP1_IN, icc_reply, icc_tx_size); - SetEPTxValid (ENDP1); + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_lld_write (c->epi->ep_num, icc_reply, ICC_MSG_HEADER_SIZE); } -static Thread *gpg_thread; static WORKING_AREA(waGPGthread, 128*16); extern msg_t GPGthread (void *arg); /* Send back ATR (Answer To Reset) */ enum icc_state -icc_power_on (void) +icc_power_on (struct ccid *c) { - int size_atr; + size_t size_atr = sizeof (ATR); + uint8_t p[ICC_MSG_HEADER_SIZE]; - if (gpg_thread == NULL) - gpg_thread = chThdCreateStatic (waGPGthread, sizeof(waGPGthread), - NORMALPRIO, GPGthread, (void *)icc_thread); + if (c->application == NULL) + c->application = chThdCreateStatic (waGPGthread, sizeof(waGPGthread), + NORMALPRIO, GPGthread, + (void *)c->icc_thread); - size_atr = sizeof (ATR); - icc_buffer[0] = ICC_DATA_BLOCK_RET; - icc_buffer[1] = size_atr; - icc_buffer[2] = 0x00; - icc_buffer[3] = 0x00; - icc_buffer[4] = 0x00; - icc_buffer[5] = 0x00; /* Slot */ - icc_buffer[ICC_MSG_SEQ_OFFSET] = icc_seq; - icc_buffer[ICC_MSG_STATUS_OFFSET] = 0x00; - icc_buffer[ICC_MSG_ERROR_OFFSET] = 0x00; - icc_buffer[ICC_MSG_CHAIN_OFFSET] = 0x00; - memcpy (&icc_buffer[ICC_MSG_DATA_OFFSET], ATR, size_atr); + p[0] = ICC_DATA_BLOCK_RET; + p[1] = size_atr; + p[2] = 0x00; + p[3] = 0x00; + p[4] = 0x00; + p[5] = 0x00; /* Slot */ + p[ICC_MSG_SEQ_OFFSET] = c->icc_header.seq; + p[ICC_MSG_STATUS_OFFSET] = 0x00; + p[ICC_MSG_ERROR_OFFSET] = 0x00; + p[ICC_MSG_CHAIN_OFFSET] = 0x00; - icc_next_p = NULL; /* This is a single transaction Bulk-IN */ - icc_tx_size = ICC_MSG_HEADER_SIZE + size_atr; - USB_SIL_Write (EP1_IN, icc_buffer, icc_tx_size); - SetEPTxValid (ENDP1); + usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE); + usb_lld_txcpy (ATR, c->epi->ep_num, ICC_MSG_HEADER_SIZE, size_atr); + + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_lld_tx_enable (c->epi->ep_num, ICC_MSG_HEADER_SIZE + size_atr); DEBUG_INFO ("ON\r\n"); return ICC_STATE_WAIT; } static void -icc_send_status (void) +icc_send_status (struct ccid *c) { - uint8_t *icc_reply; - - if (icc_chain_p) - icc_reply = icc_chain_p; - else - icc_reply = icc_buffer; + uint8_t icc_reply[ICC_MSG_HEADER_SIZE]; icc_reply[0] = ICC_SLOT_STATUS_RET; icc_reply[1] = 0x00; @@ -346,8 +788,8 @@ icc_send_status (void) icc_reply[3] = 0x00; icc_reply[4] = 0x00; icc_reply[5] = 0x00; /* Slot */ - icc_reply[ICC_MSG_SEQ_OFFSET] = icc_seq; - if (icc_state == ICC_STATE_START) + icc_reply[ICC_MSG_SEQ_OFFSET] = c->icc_header.seq; + if (c->icc_state == ICC_STATE_START) /* 1: ICC present but not activated 2: No ICC present */ icc_reply[ICC_MSG_STATUS_OFFSET] = 1; else @@ -356,48 +798,45 @@ icc_send_status (void) icc_reply[ICC_MSG_ERROR_OFFSET] = 0x00; icc_reply[ICC_MSG_CHAIN_OFFSET] = 0x00; - icc_next_p = NULL; /* This is a single transaction Bulk-IN */ - icc_tx_size = ICC_MSG_HEADER_SIZE; - USB_SIL_Write (EP1_IN, icc_reply, icc_tx_size); - SetEPTxValid (ENDP1); + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_lld_write (c->epi->ep_num, icc_reply, ICC_MSG_HEADER_SIZE); + led_blink (LED_SHOW_STATUS); #ifdef DEBUG_MORE DEBUG_INFO ("St\r\n"); #endif } enum icc_state -icc_power_off (void) +icc_power_off (struct ccid *c) { - icc_data_size = 0; - - if (gpg_thread) + if (c->application) { - chThdTerminate (gpg_thread); - chEvtSignal (gpg_thread, (eventmask_t)1); - chThdWait (gpg_thread); - gpg_thread = NULL; + chThdTerminate (c->application); + chEvtSignal (c->application, EV_NOP); + chThdWait (c->application); + c->application = NULL; } - icc_state = ICC_STATE_START; /* This status change should be here */ - icc_send_status (); + c->icc_state = ICC_STATE_START; /* This status change should be here */ + icc_send_status (c); DEBUG_INFO ("OFF\r\n"); return ICC_STATE_START; } -int res_APDU_size; -const uint8_t *res_APDU_pointer; - static void -icc_send_data_block (int len, uint8_t status, uint8_t chain) +icc_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error) { int tx_size = USB_LL_BUF_SIZE; - uint8_t *p; + uint8_t p[ICC_MSG_HEADER_SIZE]; + size_t len; - if (icc_chain_p) - p = icc_chain_p; + if (status == 0) + len = c->a->res_apdu_data_len + 2; else - p = icc_buffer; + len = 0; p[0] = ICC_DATA_BLOCK_RET; p[1] = len & 0xFF; @@ -405,247 +844,418 @@ icc_send_data_block (int len, uint8_t status, uint8_t chain) p[3] = (len >> 16)& 0xFF; p[4] = (len >> 24)& 0xFF; p[5] = 0x00; /* Slot */ - p[ICC_MSG_SEQ_OFFSET] = icc_seq; + p[ICC_MSG_SEQ_OFFSET] = c->a->seq; p[ICC_MSG_STATUS_OFFSET] = status; - p[ICC_MSG_ERROR_OFFSET] = 0; - p[ICC_MSG_CHAIN_OFFSET] = chain; + p[ICC_MSG_ERROR_OFFSET] = error; + p[ICC_MSG_CHAIN_OFFSET] = 0; - icc_tx_size = ICC_MSG_HEADER_SIZE + len; - if (icc_tx_size < USB_LL_BUF_SIZE) + usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE); + if (len == 0) { - icc_next_p = NULL; - tx_size = icc_tx_size; + usb_lld_tx_enable (c->epi->ep_num, ICC_MSG_HEADER_SIZE); + return; + } + + if (ICC_MSG_HEADER_SIZE + len <= USB_LL_BUF_SIZE) + { + usb_lld_txcpy (c->a->res_apdu_data, c->epi->ep_num, + ICC_MSG_HEADER_SIZE, c->a->res_apdu_data_len); + usb_lld_txcpy (c->sw1sw2, c->epi->ep_num, + ICC_MSG_HEADER_SIZE + c->a->res_apdu_data_len, 2); + c->epi->buf = NULL; + if (ICC_MSG_HEADER_SIZE + len < USB_LL_BUF_SIZE) + c->epi->tx_done = 1; + tx_size = ICC_MSG_HEADER_SIZE + len; + } + else if (ICC_MSG_HEADER_SIZE + len - 1 == USB_LL_BUF_SIZE) + { + usb_lld_txcpy (c->a->res_apdu_data, c->epi->ep_num, + ICC_MSG_HEADER_SIZE, c->a->res_apdu_data_len); + usb_lld_txcpy (c->sw1sw2, c->epi->ep_num, + ICC_MSG_HEADER_SIZE + c->a->res_apdu_data_len, 1); + c->epi->buf = &c->sw1sw2[1]; + c->epi->cnt = 1; + c->epi->buf_len = 1; + c->epi->next_buf = no_buf; + } + else if (ICC_MSG_HEADER_SIZE + len - 2 == USB_LL_BUF_SIZE) + { + usb_lld_txcpy (c->a->res_apdu_data, c->epi->ep_num, + ICC_MSG_HEADER_SIZE, c->a->res_apdu_data_len); + c->epi->buf = &c->sw1sw2[0]; + c->epi->cnt = 0; + c->epi->buf_len = 2; + c->epi->next_buf = no_buf; } else - icc_next_p = p + USB_LL_BUF_SIZE; + { + usb_lld_txcpy (c->a->res_apdu_data, c->epi->ep_num, ICC_MSG_HEADER_SIZE, + USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE); + c->epi->buf = c->a->res_apdu_data + USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE; + c->epi->cnt = USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE; + c->epi->buf_len = c->a->res_apdu_data_len + - (USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE); + c->epi->next_buf = get_sw1sw2; + } - USB_SIL_Write (EP1_IN, p, tx_size); - SetEPTxValid (ENDP1); + usb_lld_tx_enable (c->epi->ep_num, tx_size); #ifdef DEBUG_MORE DEBUG_INFO ("DATA\r\n"); #endif } static void -icc_send_params (void) +icc_send_data_block (struct ccid *c) { - icc_buffer[0] = ICC_PARAMS_RET; - icc_buffer[1] = 0x07; /* Length = 0x00000007 */ - icc_buffer[2] = 0; - icc_buffer[3] = 0; - icc_buffer[4] = 0; - icc_buffer[5] = 0x00; /* Slot */ - icc_buffer[ICC_MSG_SEQ_OFFSET] = icc_seq; - icc_buffer[ICC_MSG_STATUS_OFFSET] = 0; - icc_buffer[ICC_MSG_ERROR_OFFSET] = 0; - icc_buffer[ICC_MSG_CHAIN_OFFSET] = 0x01; /* ProtocolNum: T=1 */ - icc_buffer[ICC_MSG_DATA_OFFSET] = 0x11; /* bmFindexDindex */ - icc_buffer[ICC_MSG_DATA_OFFSET+1] = 0x11; /* bmTCCKST1 */ - icc_buffer[ICC_MSG_DATA_OFFSET+2] = 0xFE; /* bGuardTimeT1 */ - icc_buffer[ICC_MSG_DATA_OFFSET+3] = 0x55; /* bmWaitingIntegersT1 */ - icc_buffer[ICC_MSG_DATA_OFFSET+4] = 0x03; /* bClockStop */ - icc_buffer[ICC_MSG_DATA_OFFSET+5] = 0xFE; /* bIFSC */ - icc_buffer[ICC_MSG_DATA_OFFSET+6] = 0; /* bNadValue */ + icc_send_data_block_internal (c, 0, 0); +} - icc_next_p = NULL; /* This is a single transaction Bulk-IN */ - icc_tx_size = ICC_MSG_HEADER_SIZE + 7; - USB_SIL_Write (EP1_IN, icc_buffer, icc_tx_size); - SetEPTxValid (ENDP1); +static void +icc_send_data_block_time_extension (struct ccid *c) +{ + icc_send_data_block_internal (c, ICC_CMD_STATUS_TIMEEXT, 1); +} + +static void +icc_send_data_block_0x9000 (struct ccid *c) +{ + uint8_t p[ICC_MSG_HEADER_SIZE+2]; + size_t len = 2; + + p[0] = ICC_DATA_BLOCK_RET; + p[1] = len & 0xFF; + p[2] = (len >> 8)& 0xFF; + p[3] = (len >> 16)& 0xFF; + p[4] = (len >> 24)& 0xFF; + p[5] = 0x00; /* Slot */ + p[ICC_MSG_SEQ_OFFSET] = c->a->seq; + p[ICC_MSG_STATUS_OFFSET] = 0; + p[ICC_MSG_ERROR_OFFSET] = 0; + p[ICC_MSG_CHAIN_OFFSET] = 0; + p[ICC_MSG_CHAIN_OFFSET+1] = 0x90; + p[ICC_MSG_CHAIN_OFFSET+2] = 0x00; + + usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE + len); + c->epi->buf = NULL; + c->epi->tx_done = 1; + + usb_lld_tx_enable (c->epi->ep_num, ICC_MSG_HEADER_SIZE + len); #ifdef DEBUG_MORE DEBUG_INFO ("DATA\r\n"); #endif } -/* Supporting smaller buffer of libccid (<= 1.3.11) */ -#define ICC_RESPONSE_MSG_DATA_SIZE 262 +/* + * Reply to the host for "GET RESPONSE". + */ +static void +icc_send_data_block_gr (struct ccid *c, size_t chunk_len) +{ + int tx_size = USB_LL_BUF_SIZE; + uint8_t p[ICC_MSG_HEADER_SIZE]; + size_t len = chunk_len + 2; + + p[0] = ICC_DATA_BLOCK_RET; + p[1] = len & 0xFF; + p[2] = (len >> 8)& 0xFF; + p[3] = (len >> 16)& 0xFF; + p[4] = (len >> 24)& 0xFF; + p[5] = 0x00; /* Slot */ + p[ICC_MSG_SEQ_OFFSET] = c->a->seq; + p[ICC_MSG_STATUS_OFFSET] = 0; + p[ICC_MSG_ERROR_OFFSET] = 0; + p[ICC_MSG_CHAIN_OFFSET] = 0; + + usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE); + + set_sw1sw2 (c->epi); + + if (chunk_len <= USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE) + { + int size_for_sw; + + if (chunk_len <= USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE - 2) + size_for_sw = 2; + else if (chunk_len == USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE - 1) + size_for_sw = 1; + else + size_for_sw = 0; + + usb_lld_txcpy (c->p, c->epi->ep_num, ICC_MSG_HEADER_SIZE, chunk_len); + if (size_for_sw) + usb_lld_txcpy (c->sw1sw2, c->epi->ep_num, + ICC_MSG_HEADER_SIZE + chunk_len, size_for_sw); + tx_size = ICC_MSG_HEADER_SIZE + chunk_len + size_for_sw; + if (size_for_sw == 2) + { + c->epi->buf = NULL; + if (tx_size < USB_LL_BUF_SIZE) + c->epi->tx_done = 1; + /* Don't set epi->tx_done = 1, when it requires ZLP */ + } + else + { + c->epi->buf = c->sw1sw2 + size_for_sw; + c->epi->cnt = size_for_sw; + c->epi->buf_len = 2 - size_for_sw; + c->epi->next_buf = no_buf; + } + } + else + { + usb_lld_txcpy (c->p, c->epi->ep_num, ICC_MSG_HEADER_SIZE, + USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE); + c->epi->buf = c->p + USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE; + c->epi->cnt = 0; + c->epi->buf_len = chunk_len - (USB_LL_BUF_SIZE - ICC_MSG_HEADER_SIZE); + c->epi->next_buf = get_sw1sw2; + } + + c->p += chunk_len; + c->len -= chunk_len; + usb_lld_tx_enable (c->epi->ep_num, tx_size); +#ifdef DEBUG_MORE + DEBUG_INFO ("DATA\r\n"); +#endif +} + + +static void +icc_send_params (struct ccid *c) +{ + uint8_t p[ICC_MSG_HEADER_SIZE]; + const uint8_t params[] = { + 0x11, /* bmFindexDindex */ + 0x11, /* bmTCCKST1 */ + 0xFE, /* bGuardTimeT1 */ + 0x55, /* bmWaitingIntegersT1 */ + 0x03, /* bClockStop */ + 0xFE, /* bIFSC */ + 0 /* bNadValue */ + }; + + p[0] = ICC_PARAMS_RET; + p[1] = 0x07; /* Length = 0x00000007 */ + p[2] = 0; + p[3] = 0; + p[4] = 0; + p[5] = 0x00; /* Slot */ + p[ICC_MSG_SEQ_OFFSET] = c->icc_header.seq; + p[ICC_MSG_STATUS_OFFSET] = 0; + p[ICC_MSG_ERROR_OFFSET] = 0; + p[ICC_MSG_CHAIN_OFFSET] = 0x01; /* ProtocolNum: T=1 */ + + usb_lld_txcpy (p, c->epi->ep_num, 0, ICC_MSG_HEADER_SIZE); + usb_lld_txcpy (params, c->epi->ep_num, ICC_MSG_HEADER_SIZE, sizeof params); + + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_lld_tx_enable (c->epi->ep_num, ICC_MSG_HEADER_SIZE + sizeof params); +#ifdef DEBUG_MORE + DEBUG_INFO ("PARAMS\r\n"); +#endif +} + static enum icc_state -icc_handle_data (void) +icc_handle_data (struct ccid *c) { - enum icc_state next_state = icc_state; - struct icc_header *icc_header; + enum icc_state next_state = c->icc_state; - if (icc_chain_p) - icc_header = (struct icc_header *)icc_chain_p; - else - icc_header = (struct icc_header *)icc_buffer; + if (c->err != 0) + { + ccid_reset (c); + icc_error (c, ICC_OFFSET_DATA_LEN); + return next_state; + } - switch (icc_state) + switch (c->icc_state) { case ICC_STATE_START: - if (icc_header->msg_type == ICC_POWER_ON) - next_state = icc_power_on (); - else if (icc_header->msg_type == ICC_POWER_OFF) - next_state = icc_power_off (); - else if (icc_header->msg_type == ICC_SLOT_STATUS) - icc_send_status (); + if (c->icc_header.msg_type == ICC_POWER_ON) + { + ccid_reset (c); + next_state = icc_power_on (c); + } + else if (c->icc_header.msg_type == ICC_POWER_OFF) + { + ccid_reset (c); + next_state = icc_power_off (c); + } + else if (c->icc_header.msg_type == ICC_SLOT_STATUS) + icc_send_status (c); else { DEBUG_INFO ("ERR01\r\n"); - icc_error (ICC_OFFSET_CMD_NOT_SUPPORTED); + icc_error (c, ICC_OFFSET_CMD_NOT_SUPPORTED); } break; case ICC_STATE_WAIT: - if (icc_header->msg_type == ICC_POWER_ON) - /* Not in the spec., but pcscd/libccid */ - next_state = icc_power_on (); - else if (icc_header->msg_type == ICC_POWER_OFF) - next_state = icc_power_off (); - else if (icc_header->msg_type == ICC_SLOT_STATUS) - icc_send_status (); - else if (icc_header->msg_type == ICC_XFR_BLOCK) + if (c->icc_header.msg_type == ICC_POWER_ON) { - if (icc_header->param == 0) - { /* Give this message to GPG thread */ - chEvtSignal (gpg_thread, (eventmask_t)1); - next_state = ICC_STATE_EXECUTE; - } - else if (icc_header->param == 1) + /* Not in the spec., but pcscd/libccid */ + ccid_reset (c); + next_state = icc_power_on (c); + } + else if (c->icc_header.msg_type == ICC_POWER_OFF) + { + ccid_reset (c); + next_state = icc_power_off (c); + } + else if (c->icc_header.msg_type == ICC_SLOT_STATUS) + icc_send_status (c); + else if (c->icc_header.msg_type == ICC_XFR_BLOCK) + { + if (c->icc_header.param == 0) { - icc_chain_p = icc_next_p; - icc_send_data_block (0, 0, 0x10); - next_state = ICC_STATE_RECEIVE; + if ((c->a->cmd_apdu_head[0] & 0x10) == 0) + { + if (c->state == APDU_STATE_COMMAND_CHAINING) + { /* command chaining finished */ + c->p += c->a->cmd_apdu_head[4]; + c->a->cmd_apdu_head[4] = 0; + DEBUG_INFO ("CMD chaning finished.\r\n"); + } + + if (c->a->cmd_apdu_head[1] == INS_GET_RESPONSE + && c->state == APDU_STATE_RESULT_GET_RESPONSE) + { + size_t len = c->a->expected_res_size; + + if (c->len <= c->a->expected_res_size) + len = c->len; + + icc_send_data_block_gr (c, len); + if (c->len == 0) + c->state = APDU_STATE_RESULT; + c->icc_state = ICC_STATE_WAIT; + DEBUG_INFO ("GET Response.\r\n"); + } + else + { /* Give this message to GPG thread */ + c->state = APDU_STATE_COMMAND_RECEIVED; + + c->a->sw = 0x9000; + c->a->res_apdu_data_len = 0; + c->a->res_apdu_data = &icc_buffer[5]; + + chEvtSignal (c->application, EV_CMD_AVAILABLE); + next_state = ICC_STATE_EXECUTE; + } + } + else + { + if (c->state == APDU_STATE_WAIT_COMMAND) + { /* command chaining is started */ + c->a->cmd_apdu_head[0] &= ~0x10; + memcpy (c->chained_cls_ins_p1_p2, c->a->cmd_apdu_head, 4); + c->state = APDU_STATE_COMMAND_CHAINING; + } + + c->p += c->a->cmd_apdu_head[4]; + c->len -= c->a->cmd_apdu_head[4]; + icc_send_data_block_0x9000 (c); + DEBUG_INFO ("CMD chaning...\r\n"); + } } else - { + { /* ICC block chaining is not supported. */ DEBUG_INFO ("ERR02\r\n"); - icc_error (ICC_OFFSET_PARAM); + icc_error (c, ICC_OFFSET_PARAM); } } - else if (icc_header->msg_type == ICC_SET_PARAMS - || icc_header->msg_type == ICC_GET_PARAMS) - icc_send_params (); - else if (icc_header->msg_type == ICC_SECURE) + else if (c->icc_header.msg_type == ICC_SET_PARAMS + || c->icc_header.msg_type == ICC_GET_PARAMS) + icc_send_params (c); + else if (c->icc_header.msg_type == ICC_SECURE) { - if (icc_buffer[10] == 0x00) /* PIN verification */ + if (c->p != c->a->cmd_apdu_data) { - cmd_APDU[0] = icc_buffer[25]; - cmd_APDU[1] = icc_buffer[26]; - cmd_APDU[2] = icc_buffer[27]; - cmd_APDU[3] = icc_buffer[28]; - icc_data_size = 4; - chEvtSignal (gpg_thread, (eventmask_t)1); + /* SECURE received in the middle of command chaining */ + ccid_reset (c); + icc_error (c, ICC_OFFSET_DATA_LEN); + return next_state; + } + + if (c->p[10-10] == 0x00) /* PIN verification */ + { + c->a->cmd_apdu_head[0] = c->p[25-10]; + c->a->cmd_apdu_head[1] = c->p[26-10]; + c->a->cmd_apdu_head[2] = c->p[27-10]; + c->a->cmd_apdu_head[3] = c->p[28-10]; + /**/ + c->a->cmd_apdu_data[0] = 0; /* bConfirmPIN */ + c->a->cmd_apdu_data[1] = c->p[17-10]; /* bEntryValidationCondition */ + c->a->cmd_apdu_data[2] = c->p[18-10]; /* bNumberMessage */ + c->a->cmd_apdu_data[3] = c->p[19-10]; /* wLangId L */ + c->a->cmd_apdu_data[4] = c->p[20-10]; /* wLangId H */ + c->a->cmd_apdu_data[5] = c->p[21-10]; /* bMsgIndex */ + + c->a->cmd_apdu_data_len = 6; + c->a->expected_res_size = 0; + + c->a->sw = 0x9000; + c->a->res_apdu_data_len = 0; + c->a->res_apdu_data = &c->p[5]; + + chEvtSignal (c->application, EV_VERIFY_CMD_AVAILABLE); next_state = ICC_STATE_EXECUTE; } - else if (icc_buffer[10] == 0x01) /* PIN Modification */ + else if (c->p[10-10] == 0x01) /* PIN Modification */ { - uint8_t num_msgs = icc_buffer[21]; + uint8_t num_msgs = c->p[21-10]; if (num_msgs == 0x00) num_msgs = 1; else if (num_msgs == 0xff) num_msgs = 3; - cmd_APDU[0] = icc_buffer[27 + num_msgs]; - cmd_APDU[1] = icc_buffer[28 + num_msgs]; - cmd_APDU[2] = icc_buffer[29 + num_msgs]; - cmd_APDU[3] = icc_buffer[30 + num_msgs]; - icc_data_size = 4; - chEvtSignal (gpg_thread, (eventmask_t)1); + c->a->cmd_apdu_head[0] = c->p[27 + num_msgs-10]; + c->a->cmd_apdu_head[1] = c->p[28 + num_msgs-10]; + c->a->cmd_apdu_head[2] = c->p[29 + num_msgs-10]; + c->a->cmd_apdu_head[3] = c->p[30 + num_msgs-10]; + /**/ + c->a->cmd_apdu_data[0] = c->p[19-10]; /* bConfirmPIN */ + c->a->cmd_apdu_data[1] = c->p[20-10]; /* bEntryValidationCondition */ + c->a->cmd_apdu_data[2] = c->p[21-10]; /* bNumberMessage */ + c->a->cmd_apdu_data[3] = c->p[22-10]; /* wLangId L */ + c->a->cmd_apdu_data[4] = c->p[23-10]; /* wLangId H */ + c->a->cmd_apdu_data[5] = c->p[24-10]; /* bMsgIndex, bMsgIndex1 */ + if (num_msgs >= 2) + c->a->cmd_apdu_data[6] = c->p[25-10]; /* bMsgIndex2 */ + if (num_msgs == 3) + c->a->cmd_apdu_data[7] = c->p[26-10]; /* bMsgIndex3 */ + + c->a->cmd_apdu_data_len = 5 + num_msgs; + c->a->expected_res_size = 0; + + c->a->sw = 0x9000; + c->a->res_apdu_data_len = 0; + c->a->res_apdu_data = &icc_buffer[5]; + + chEvtSignal (c->application, EV_MODIFY_CMD_AVAILABLE); next_state = ICC_STATE_EXECUTE; } else - icc_error (ICC_MSG_DATA_OFFSET); + icc_error (c, ICC_MSG_DATA_OFFSET); } else { DEBUG_INFO ("ERR03\r\n"); - DEBUG_BYTE (icc_header->msg_type); - icc_error (ICC_OFFSET_CMD_NOT_SUPPORTED); - } - break; - case ICC_STATE_RECEIVE: - if (icc_header->msg_type == ICC_POWER_OFF) - { - icc_chain_p = NULL; - next_state = icc_power_off (); - } - else if (icc_header->msg_type == ICC_SLOT_STATUS) - icc_send_status (); - else if (icc_header->msg_type == ICC_XFR_BLOCK) - { - if (icc_header->param == 2) /* Got the final block */ - { /* Give this message to GPG thread */ - int len = icc_next_p - icc_chain_p - ICC_MSG_HEADER_SIZE; - - memmove (icc_chain_p, icc_chain_p + ICC_MSG_HEADER_SIZE, len); - icc_next_p -= ICC_MSG_HEADER_SIZE; - icc_data_size = icc_next_p - icc_buffer - ICC_MSG_HEADER_SIZE; - icc_chain_p = NULL; - next_state = ICC_STATE_EXECUTE; - chEvtSignal (gpg_thread, (eventmask_t)1); - } - else /* icc_header->param == 3 is not supported. */ - { - DEBUG_INFO ("ERR08\r\n"); - icc_error (ICC_OFFSET_PARAM); - } - } - else - { - DEBUG_INFO ("ERR05\r\n"); - DEBUG_BYTE (icc_header->msg_type); - icc_chain_p = NULL; - icc_error (ICC_OFFSET_CMD_NOT_SUPPORTED); - next_state = ICC_STATE_WAIT; + DEBUG_BYTE (c->icc_header.msg_type); + icc_error (c, ICC_OFFSET_CMD_NOT_SUPPORTED); } break; case ICC_STATE_EXECUTE: - if (icc_header->msg_type == ICC_POWER_OFF) - next_state = icc_power_off (); - else if (icc_header->msg_type == ICC_SLOT_STATUS) - icc_send_status (); + if (c->icc_header.msg_type == ICC_POWER_OFF) + next_state = icc_power_off (c); + else if (c->icc_header.msg_type == ICC_SLOT_STATUS) + icc_send_status (c); else { DEBUG_INFO ("ERR04\r\n"); - DEBUG_BYTE (icc_header->msg_type); - icc_error (ICC_OFFSET_CMD_NOT_SUPPORTED); - } - break; - case ICC_STATE_SEND: - if (icc_header->msg_type == ICC_POWER_OFF) - next_state = icc_power_off (); - else if (icc_header->msg_type == ICC_SLOT_STATUS) - icc_send_status (); - else if (icc_header->msg_type == ICC_XFR_BLOCK) - { - if (icc_header->param == 0x10) - { - if (res_APDU_pointer != NULL) - { - memcpy (res_APDU, res_APDU_pointer, - ICC_RESPONSE_MSG_DATA_SIZE); - res_APDU_pointer += ICC_RESPONSE_MSG_DATA_SIZE; - } - else - memmove (res_APDU, res_APDU+ICC_RESPONSE_MSG_DATA_SIZE, - res_APDU_size); - - if (res_APDU_size <= ICC_RESPONSE_MSG_DATA_SIZE) - { - icc_send_data_block (res_APDU_size, 0, 0x02); - next_state = ICC_STATE_WAIT; - } - else - { - icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x03); - res_APDU_size -= ICC_RESPONSE_MSG_DATA_SIZE; - } - } - else - { - DEBUG_INFO ("ERR0A\r\n"); - DEBUG_BYTE (icc_header->param >> 8); - DEBUG_BYTE (icc_header->param & 0xff); - icc_error (ICC_OFFSET_PARAM); - next_state = ICC_STATE_WAIT; - } - } - else - { - DEBUG_INFO ("ERR06\r\n"); - DEBUG_BYTE (icc_header->msg_type); - icc_error (ICC_OFFSET_CMD_NOT_SUPPORTED); - next_state = ICC_STATE_WAIT; + DEBUG_BYTE (c->icc_header.msg_type); + icc_error (c, ICC_OFFSET_CMD_NOT_SUPPORTED); } break; default: @@ -658,14 +1268,15 @@ icc_handle_data (void) } static enum icc_state -icc_handle_timeout (void) +icc_handle_timeout (struct ccid *c) { - enum icc_state next_state = icc_state; + enum icc_state next_state = c->icc_state; - switch (icc_state) + switch (c->icc_state) { case ICC_STATE_EXECUTE: - icc_send_data_block (0, ICC_CMD_STATUS_TIMEEXT, 0); + icc_send_data_block_time_extension (c); + led_blink (LED_ONESHOT); break; default: break; @@ -676,17 +1287,29 @@ icc_handle_timeout (void) #define USB_ICC_TIMEOUT MS2ST(1950) + +static struct ccid ccid; + +#define GPG_THREAD_TERMINATED 0xffff + msg_t USBthread (void *arg) { + struct ep_in *epi = &endpoint_in; + struct ep_out *epo = &endpoint_out; + struct ccid *c = &ccid; + struct apdu *a = &apdu; + (void)arg; - icc_thread = chThdSelf (); + epi_init (epi, ENDP1, notify_tx, c); + epo_init (epo, ENDP1, notify_icc, c); + ccid_init (c, epi, epo, a, chThdSelf ()); + apdu_init (a); + chEvtClear (ALL_EVENTS); - icc_state = ICC_STATE_START; - - icc_prepare_receive (0); + icc_prepare_receive (c); while (1) { eventmask_t m; @@ -694,42 +1317,62 @@ USBthread (void *arg) m = chEvtWaitOneTimeout (ALL_EVENTS, USB_ICC_TIMEOUT); if (m == EV_RX_DATA_READY) - icc_state = icc_handle_data (); + c->icc_state = icc_handle_data (c); else if (m == EV_EXEC_FINISHED) - if (icc_state == ICC_STATE_EXECUTE) + if (c->icc_state == ICC_STATE_EXECUTE) { - if (res_APDU_pointer != NULL) + if (c->a->sw == GPG_THREAD_TERMINATED) { - memcpy (res_APDU, res_APDU_pointer, ICC_RESPONSE_MSG_DATA_SIZE); - res_APDU_pointer += ICC_RESPONSE_MSG_DATA_SIZE; + c->sw1sw2[0] = 0x90; + c->sw1sw2[1] = 0x00; + c->state = APDU_STATE_RESULT; + icc_send_data_block (c); + c->icc_state = ICC_STATE_EXITED; + break; } - if (res_APDU_size <= ICC_RESPONSE_MSG_DATA_SIZE) + c->a->cmd_apdu_data_len = 0; + c->sw1sw2[0] = c->a->sw >> 8; + c->sw1sw2[1] = c->a->sw & 0xff; + + if (c->a->res_apdu_data_len <= c->a->expected_res_size) { - icc_send_data_block (res_APDU_size, 0, 0); - icc_state = ICC_STATE_WAIT; + c->state = APDU_STATE_RESULT; + icc_send_data_block (c); + c->icc_state = ICC_STATE_WAIT; } else { - icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x01); - res_APDU_size -= ICC_RESPONSE_MSG_DATA_SIZE; - icc_state = ICC_STATE_SEND; + c->state = APDU_STATE_RESULT_GET_RESPONSE; + c->p = c->a->res_apdu_data; + c->len = c->a->res_apdu_data_len; + icc_send_data_block_gr (c, c->a->expected_res_size); + c->icc_state = ICC_STATE_WAIT; } } else - { /* XXX: error */ + { DEBUG_INFO ("ERR07\r\n"); } else if (m == EV_TX_FINISHED) { - if (icc_state == ICC_STATE_START || icc_state == ICC_STATE_WAIT - || icc_state == ICC_STATE_SEND) - icc_prepare_receive (0); - else if (icc_state == ICC_STATE_RECEIVE) - icc_prepare_receive (1); + if (c->state == APDU_STATE_RESULT) + { + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + c->err = 0; + c->a->cmd_apdu_data_len = 0; + c->a->expected_res_size = 0; + } + + if (c->state == APDU_STATE_WAIT_COMMAND + || c->state == APDU_STATE_COMMAND_CHAINING + || c->state == APDU_STATE_RESULT_GET_RESPONSE) + icc_prepare_receive (c); } else /* Timeout */ - icc_state = icc_handle_timeout (); + c->icc_state = icc_handle_timeout (c); } return 0; diff --git a/src/usb-msc.c b/src/usb-msc.c new file mode 100644 index 0000000..cacef7a --- /dev/null +++ b/src/usb-msc.c @@ -0,0 +1,550 @@ +/* + * usb-msc.c -- USB Mass Storage Class protocol handling + * + * Copyright (C) 2011, 2012 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 . + * + */ + +#include "config.h" +#include "ch.h" +#include "gnuk.h" +#include "usb_lld.h" +#include "usb-msc.h" + +struct usb_endp_in { + const uint8_t *txbuf; /* Pointer to the transmission buffer. */ + size_t txsize; /* Transmit transfer size remained. */ + size_t txcnt; /* Transmitted bytes so far. */ +}; + +struct usb_endp_out { + uint8_t *rxbuf; /* Pointer to the receive buffer. */ + size_t rxsize; /* Requested receive transfer size. */ + size_t rxcnt; /* Received bytes so far. */ +}; + +static struct usb_endp_in ep6_in; +static struct usb_endp_out ep6_out; + +static Thread *the_thread; + +#define ENDP_MAX_SIZE 64 + +static uint8_t msc_state; + + +static void usb_start_transmit (const uint8_t *p, size_t n) +{ + size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n; + + ep6_in.txbuf = p; + ep6_in.txsize = n; + ep6_in.txcnt = 0; + + usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, pkt_len); +} + +/* "Data Transmitted" callback */ +void EP6_IN_Callback (void) +{ + size_t n = (size_t)usb_lld_tx_data_len (ENDP6); + + ep6_in.txbuf += n; + ep6_in.txcnt += n; + ep6_in.txsize -= n; + + if (ep6_in.txsize > 0) /* More data to be sent */ + { + if (ep6_in.txsize > ENDP_MAX_SIZE) + n = ENDP_MAX_SIZE; + else + n = ep6_in.txsize; + usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, n); + return; + } + + /* Transmit has been completed, notify the waiting thread */ + switch (msc_state) + { + case MSC_SENDING_CSW: + case MSC_DATA_IN: + if (the_thread != NULL) { + Thread *tp; + chSysLockFromIsr (); + tp = the_thread; + the_thread = NULL; + tp->p_u.rdymsg = RDY_OK; + chSchReadyI (tp); + chSysUnlockFromIsr (); + } + break; + default: + break; + } +} + + +static void usb_start_receive (uint8_t *p, size_t n) +{ + ep6_out.rxbuf = p; + ep6_out.rxsize = n; + ep6_out.rxcnt = 0; + usb_lld_rx_enable (ENDP6); +} + +/* "Data Received" call back */ +void EP6_OUT_Callback (void) +{ + size_t n = (size_t)usb_lld_rx_data_len (ENDP6); + int err = 0; + + if (n > ep6_out.rxsize) + { /* buffer overflow */ + err = 1; + n = ep6_out.rxsize; + } + + usb_lld_rxcpy (ep6_out.rxbuf, ENDP6, 0, n); + ep6_out.rxbuf += n; + ep6_out.rxcnt += n; + ep6_out.rxsize -= n; + + if (n == ENDP_MAX_SIZE && ep6_out.rxsize != 0) + { /* More data to be received */ + usb_lld_rx_enable (ENDP6); + return; + } + + /* Receiving has been completed, notify the waiting thread */ + switch (msc_state) + { + case MSC_IDLE: + case MSC_DATA_OUT: + if (the_thread != NULL) { + Thread *tp; + chSysLockFromIsr (); + tp = the_thread; + the_thread = NULL; + tp->p_u.rdymsg = err? RDY_RESET : RDY_OK; + chSchReadyI (tp); + chSysUnlockFromIsr (); + } + break; + default: + break; + } +} + +static const uint8_t scsi_inquiry_data_00[] = { 0, 0, 0, 0, 0 }; + +static const uint8_t scsi_inquiry_data[] = { + 0x00, /* Direct Access Device. */ + 0x80, /* RMB = 1: Removable Medium. */ + 0x05, /* Version: SPC-3. */ + 0x02, /* Response format: SPC-3. */ + 36 - 4, /* Additional Length. */ + 0x00, + 0x00, + 0x00, + /* Vendor Identification */ + 'F', 'S', 'I', 'J', ' ', ' ', ' ', ' ', + /* Product Identification */ + 'V', 'i', 'r', 't', 'u', 'a', 'l', ' ', + 'D', 'i', 's', 'k', ' ', ' ', ' ', ' ', + /* Product Revision Level */ + '1', '.', '0', ' ' +}; + +static uint8_t scsi_sense_data_desc[] = { + 0x72, /* Response Code: descriptor, current */ + 0x02, /* Sense Key */ + 0x3a, /* ASC (additional sense code) */ + 0x00, /* ASCQ (additional sense code qualifier) */ + 0x00, 0x00, 0x00, + 0x00, /* Additional Sense Length */ +}; + +static uint8_t scsi_sense_data_fixed[] = { + 0x70, /* Response Code: fixed, current */ + 0x00, + 0x02, /* Sense Key */ + 0x00, 0x00, 0x00, 0x00, + 0x0a, /* Additional Sense Length */ + 0x00, 0x00, 0x00, 0x00, + 0x3a, /* ASC (additional sense code) */ + 0x00, /* ASCQ (additional sense code qualifier) */ + 0x00, + 0x00, 0x00, 0x00, +}; + +static void set_scsi_sense_data(uint8_t sense_key, uint8_t asc) { + scsi_sense_data_desc[1] = scsi_sense_data_fixed[2] = sense_key; + scsi_sense_data_desc[2] = scsi_sense_data_fixed[12] = asc; +} + + +static uint8_t buf[512]; + +static uint8_t contingent_allegiance; +static uint8_t keep_contingent_allegiance; + +uint8_t media_available; + +void msc_media_insert_change (int available) +{ + contingent_allegiance = 1; + media_available = available; + if (available) + { + set_scsi_sense_data (0x06, 0x28); /* UNIT_ATTENTION */ + keep_contingent_allegiance = 0; + } + else + { + set_scsi_sense_data (0x02, 0x3a); /* NOT_READY */ + keep_contingent_allegiance = 1; + } +} + + +static uint8_t scsi_read_format_capacities (uint32_t *nblocks, + uint32_t *secsize) +{ + *nblocks = 68; + *secsize = 512; + if (media_available) + return 2; /* Formatted Media.*/ + else + return 3; /* No Media.*/ +} + +static struct CBW CBW; + +static struct CSW CSW; + + +static int msc_recv_data (void) +{ + msg_t msg; + + chSysLock (); + msc_state = MSC_DATA_OUT; + the_thread = chThdSelf (); + usb_start_receive (buf, 512); + chSchGoSleepS (THD_STATE_SUSPENDED); + msg = chThdSelf ()->p_u.rdymsg; + chSysUnlock (); + return 0; +} + +static void msc_send_data (const uint8_t *p, size_t n) +{ + msg_t msg; + + chSysLock (); + msc_state = MSC_DATA_IN; + the_thread = chThdSelf (); + usb_start_transmit (p, n); + chSchGoSleepS (THD_STATE_SUSPENDED); + msg = chThdSelf ()->p_u.rdymsg; + CSW.dCSWDataResidue -= (uint32_t)n; + chSysUnlock(); +} + +static void msc_send_result (const uint8_t *p, size_t n) +{ + msg_t msg; + + if (p != NULL) + { + if (n > CBW.dCBWDataTransferLength) + n = CBW.dCBWDataTransferLength; + + CSW.dCSWDataResidue = CBW.dCBWDataTransferLength; + msc_send_data (p, n); + CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; + } + + CSW.dCSWSignature = MSC_CSW_SIGNATURE; + chSysLock (); + msc_state = MSC_SENDING_CSW; + the_thread = chThdSelf (); + usb_start_transmit ((uint8_t *)&CSW, sizeof CSW); + chSchGoSleepS (THD_STATE_SUSPENDED); + msg = chThdSelf ()->p_u.rdymsg; + chSysUnlock (); +} + + + +void msc_handle_command (void) +{ + size_t n; + uint32_t nblocks, secsize; + uint32_t lba; + int r; + msg_t msg; + + chSysLock(); + msc_state = MSC_IDLE; + the_thread = chThdSelf (); + usb_start_receive ((uint8_t *)&CBW, sizeof CBW); + chSchGoSleepTimeoutS (THD_STATE_SUSPENDED, MS2ST (1000)); + msg = chThdSelf ()->p_u.rdymsg; + chSysUnlock (); + + if (msg != RDY_OK) + { + /* Error occured, ignore the request and go into error state */ + msc_state = MSC_ERROR; + if (msg != RDY_TIMEOUT) + { + chSysLock (); + usb_lld_stall_rx (ENDP6); + chSysUnlock (); + } + return; + } + + n = ep6_out.rxcnt; + + if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE)) + { + msc_state = MSC_ERROR; + chSysLock (); + usb_lld_stall_rx (ENDP6); + chSysUnlock (); + return; + } + + CSW.dCSWTag = CBW.dCBWTag; + switch (CBW.CBWCB[0]) { + case SCSI_REQUEST_SENSE: + if (CBW.CBWCB[1] & 0x01) /* DESC */ + msc_send_result ((uint8_t *)&scsi_sense_data_desc, + sizeof scsi_sense_data_desc); + else + msc_send_result ((uint8_t *)&scsi_sense_data_fixed, + sizeof scsi_sense_data_fixed); + /* After the error is reported, clear it, if it's . */ + if (!keep_contingent_allegiance) + { + contingent_allegiance = 0; + set_scsi_sense_data (0x00, 0x00); + } + return; + case SCSI_INQUIRY: + if (CBW.CBWCB[1] & 0x01) /* EVPD */ + /* assume page 00 */ + msc_send_result ((uint8_t *)&scsi_inquiry_data_00, + sizeof scsi_inquiry_data_00); + else + msc_send_result ((uint8_t *)&scsi_inquiry_data, + sizeof scsi_inquiry_data); + return; + case SCSI_READ_FORMAT_CAPACITIES: + buf[8] = scsi_read_format_capacities (&nblocks, &secsize); + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; + buf[4] = (uint8_t)(nblocks >> 24); + buf[5] = (uint8_t)(nblocks >> 16); + buf[6] = (uint8_t)(nblocks >> 8); + buf[7] = (uint8_t)(nblocks >> 0); + buf[9] = (uint8_t)(secsize >> 16); + buf[10] = (uint8_t)(secsize >> 8); + buf[11] = (uint8_t)(secsize >> 0); + msc_send_result (buf, 12); + return; + case SCSI_START_STOP_UNIT: + if (CBW.CBWCB[4] == 0x00 /* stop */ + || CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */) + { + msc_scsi_stop (CBW.CBWCB[4]); + set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */ + contingent_allegiance = 1; + keep_contingent_allegiance = 1; + } + /* CBW.CBWCB[4] == 0x01 *//* start */ + goto success; + case SCSI_TEST_UNIT_READY: + if (contingent_allegiance) + { + CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; + CSW.dCSWDataResidue = 0; + msc_send_result (NULL, 0); + return; + } + /* fall through */ + success: + case SCSI_SYNCHRONIZE_CACHE: + case SCSI_VERIFY10: + case SCSI_ALLOW_MEDIUM_REMOVAL: + CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; + CSW.dCSWDataResidue = CBW.dCBWDataTransferLength; + msc_send_result (NULL, 0); + return; + case SCSI_MODE_SENSE6: + buf[0] = 0x03; + buf[1] = buf[2] = buf[3] = 0; + msc_send_result (buf, 4); + return; + case SCSI_READ_CAPACITY10: + scsi_read_format_capacities (&nblocks, &secsize); + buf[0] = (uint8_t)((nblocks - 1) >> 24); + buf[1] = (uint8_t)((nblocks - 1) >> 16); + buf[2] = (uint8_t)((nblocks - 1) >> 8); + buf[3] = (uint8_t)((nblocks - 1) >> 0); + buf[4] = (uint8_t)(secsize >> 24); + buf[5] = (uint8_t)(secsize >> 16); + buf[6] = (uint8_t)(secsize >> 8); + buf[7] = (uint8_t)(secsize >> 0); + msc_send_result (buf, 8); + return; + case SCSI_READ10: + case SCSI_WRITE10: + break; + default: + if (CBW.dCBWDataTransferLength == 0) + { + CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; + CSW.dCSWDataResidue = 0; + msc_send_result (NULL, 0); + return; + } + else + { + msc_state = MSC_ERROR; + chSysLock (); + usb_lld_stall_tx (ENDP6); + usb_lld_stall_rx (ENDP6); + chSysUnlock (); + return; + } + } + + lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16) + | (CBW.CBWCB[4] << 8) | CBW.CBWCB[5]; + + /* Transfer direction.*/ + if (CBW.bmCBWFlags & 0x80) + { + /* IN, Device to Host.*/ + msc_state = MSC_DATA_IN; + if (CBW.CBWCB[0] == SCSI_READ10) + { + const uint8_t *p; + + CSW.dCSWDataResidue = 0; + while (1) + { + if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0) + { + CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; + break; + } + + if ((r = msc_scsi_read (lba, &p)) == 0) + { + msc_send_data (p, 512); + if (++CBW.CBWCB[5] == 0) + if (++CBW.CBWCB[4] == 0) + if (++CBW.CBWCB[3] == 0) + ++CBW.CBWCB[2]; + if (CBW.CBWCB[8]-- == 0) + CBW.CBWCB[7]--; + CSW.dCSWDataResidue += 512; + } + else + { + CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; + contingent_allegiance = 1; + if (r == SCSI_ERROR_NOT_READY) + set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a); + else + set_scsi_sense_data (r, 0x00); + break; + } + } + + msc_send_result (NULL, 0); + } + } + else + { + /* OUT, Host to Device.*/ + if (CBW.CBWCB[0] == SCSI_WRITE10) + { + CSW.dCSWDataResidue = CBW.dCBWDataTransferLength; + + while (1) + { + if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0) + { + CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; + break; + } + + msc_recv_data (); + if ((r = msc_scsi_write (lba, buf, 512)) == 0) + { + if (++CBW.CBWCB[5] == 0) + if (++CBW.CBWCB[4] == 0) + if (++CBW.CBWCB[3] == 0) + ++CBW.CBWCB[2]; + if (CBW.CBWCB[8]-- == 0) + CBW.CBWCB[7]--; + CSW.dCSWDataResidue -= 512; + } + else + { + CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; + contingent_allegiance = 1; + if (r == SCSI_ERROR_NOT_READY) + set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a); + else + set_scsi_sense_data (r, 0x00); + break; + } + } + + msc_send_result (NULL, 0); + } + } +} + +static msg_t +msc_main (void *arg) +{ + (void)arg; + + /* Initially, it starts with no media */ + msc_media_insert_change (0); + while (1) + msc_handle_command (); + + return 0; +} + +static WORKING_AREA(wa_msc_thread, 128); + +void msc_init (void) +{ + chThdCreateStatic (wa_msc_thread, sizeof (wa_msc_thread), + NORMALPRIO, msc_main, NULL); +} diff --git a/src/usb-msc.h b/src/usb-msc.h new file mode 100644 index 0000000..567e4dc --- /dev/null +++ b/src/usb-msc.h @@ -0,0 +1,52 @@ +#define MSC_CBW_SIGNATURE 0x43425355 +#define MSC_CSW_SIGNATURE 0x53425355 + +#define MSC_GET_MAX_LUN_COMMAND 0xFE +#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF + +#define MSC_CSW_STATUS_PASSED 0 +#define MSC_CSW_STATUS_FAILED 1 + +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SENSE6 0x1A +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_READ10 0x28 +#define SCSI_READ_CAPACITY10 0x25 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_WRITE10 0x2A +#define SCSI_VERIFY10 0x2F +#define SCSI_READ_FORMAT_CAPACITIES 0x23 + +#define SCSI_SYNCHRONIZE_CACHE 0x35 + +#define MSC_IDLE 0 +#define MSC_DATA_OUT 1 +#define MSC_DATA_IN 2 +#define MSC_SENDING_CSW 3 +#define MSC_ERROR 4 + +struct CBW { + uint32_t dCBWSignature; + uint32_t dCBWTag; + uint32_t dCBWDataTransferLength; + uint8_t bmCBWFlags; + uint8_t bCBWLUN; + uint8_t bCBWCBLength; + uint8_t CBWCB[16]; +} __attribute__((packed)); + +struct CSW { + uint32_t dCSWSignature; + uint32_t dCSWTag; + uint32_t dCSWDataResidue; + uint8_t bCSWStatus; +} __attribute__((packed)); + +#define SCSI_ERROR_NOT_READY 2 +#define SCSI_ERROR_ILLEAGAL_REQUEST 5 +#define SCSI_ERROR_UNIT_ATTENTION 6 +#define SCSI_ERROR_DATA_PROTECT 7 + +extern uint8_t media_available; diff --git a/src/usb_conf.h b/src/usb_conf.h index 34a9b36..75241e3 100644 --- a/src/usb_conf.h +++ b/src/usb_conf.h @@ -1,37 +1,40 @@ -/* USB configuration file for USB-FS-Device_Lib */ -/* - * For detail, please see the documentation of - * STM32F10x USB Full Speed Device Library (USB-FS-Device_Lib) - * by STMicroelectronics - */ +/* USB buffer memory definition and number of string descriptors */ #ifndef __USB_CONF_H #define __USB_CONF_H -#ifdef ENABLE_VIRTUAL_COM_PORT -#define EP_NUM (6) -#else -#define EP_NUM (3) -#endif - -#define BTABLE_ADDRESS (0x00) +#define NUM_STRING_DESC 7 +/* Control pipe */ /* EP0 */ #define ENDP0_RXADDR (0x40) #define ENDP0_TXADDR (0x80) +/* CCID/ICCD BULK_IN, BULK_OUT */ /* EP1 */ #define ENDP1_TXADDR (0xc0) +#define ENDP1_RXADDR (0x100) + +/* HID INTR_IN, INTR_OUT */ /* EP2 */ -#define ENDP2_RXADDR (0x100) +#define ENDP2_TXADDR (0x140) +#define ENDP2_RXADDR (0x148) +/* CDC BULK_IN, INTR_IN, BULK_OUT */ /* EP3 */ -#define ENDP3_TXADDR (0x140) +#define ENDP3_TXADDR (0x14a) /* EP4 */ -#define ENDP4_TXADDR (0x180) +#define ENDP4_TXADDR (0x15a) /* EP5 */ -#define ENDP5_RXADDR (0x190) +#define ENDP5_RXADDR (0x162) -#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM ) +/* 0x172 - 0x180 : 14-byte */ + +/* MSC BULK_IN, BULK_OUT */ +/* EP6 */ +#define ENDP6_TXADDR (0x180) +#define ENDP6_RXADDR (0x1c0) + +/* EP7: free */ #endif /* __USB_CONF_H */ diff --git a/src/usb_ctrl.c b/src/usb_ctrl.c new file mode 100644 index 0000000..49cb8d0 --- /dev/null +++ b/src/usb_ctrl.c @@ -0,0 +1,454 @@ +/* + * usb_ctrl.c - USB control pipe device specific code for Gnuk + * + * Copyright (C) 2010, 2011, 2012 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 . + * + */ + +/* Packet size of USB Bulk transfer for full speed */ +#define GNUK_MAX_PACKET_SIZE 64 + +#include "config.h" +#include "ch.h" +#include "hal.h" +#include "usb_lld.h" +#include "usb_conf.h" +#include "gnuk.h" + +#ifdef ENABLE_VIRTUAL_COM_PORT +#include "usb-cdc.h" + +struct line_coding +{ + uint32_t bitrate; + uint8_t format; + uint8_t paritytype; + uint8_t datatype; +}; + +static struct line_coding line_coding = { + 115200, /* baud rate: 115200 */ + 0x00, /* stop bits: 1 */ + 0x00, /* parity: none */ + 0x08 /* bits: 8 */ +}; + +static int +vcom_port_data_setup (uint8_t req, uint8_t req_no) +{ + if (USB_SETUP_GET (req)) + { + if (req_no == USB_CDC_REQ_GET_LINE_CODING) + { + usb_lld_set_data_to_send (&line_coding, sizeof(line_coding)); + return USB_SUCCESS; + } + } + else /* USB_SETUP_SET (req) */ + { + if (req_no == USB_CDC_REQ_SET_LINE_CODING) + { + usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding)); + return USB_SUCCESS; + } + else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE) + /* Do nothing and success */ + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +#define VCOM_NUM_INTERFACES 2 +#else +#define VCOM_NUM_INTERFACES 0 +#endif + +#ifdef PINPAD_DND_SUPPORT +#include "usb-msc.h" +#define MSC_NUM_INTERFACES 1 +#else +#define MSC_NUM_INTERFACES 0 +#endif + +#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES) +#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES) + +uint32_t bDeviceState = UNCONNECTED; /* USB device status */ + +static void +gnuk_setup_endpoints_for_interface (uint16_t interface, int stop) +{ + if (interface == 0) + { + if (!stop) + usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR, + GNUK_MAX_PACKET_SIZE); + else + { + usb_lld_stall_rx (ENDP1); + usb_lld_stall_tx (ENDP1); + } + } +#ifdef ENABLE_VIRTUAL_COM_PORT + else if (interface == 1) + { + if (!stop) + usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0); + else + usb_lld_stall_tx (ENDP4); + } + else if (interface == 2) + { + if (!stop) + { + usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0); + usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0, + VIRTUAL_COM_PORT_DATA_SIZE); + } + else + { + usb_lld_stall_tx (ENDP3); + usb_lld_stall_rx (ENDP5); + } + } +#endif +#ifdef PINPAD_DND_SUPPORT + else if (interface == MSC_INTERFACE_NO) + { + if (!stop) + { + usb_lld_setup_endpoint (ENDP6, EP_BULK, 0, + ENDP6_RXADDR, ENDP6_TXADDR, 64); + usb_lld_stall_rx (ENDP6); + } + else + { + usb_lld_stall_tx (ENDP6); + usb_lld_stall_rx (ENDP6); + } + } +#endif +} + +static void +gnuk_device_reset (void) +{ + int i; + + /* Set DEVICE as not configured */ + usb_lld_set_configuration (0); + + /* Current Feature initialization */ + usb_lld_set_feature (Config_Descriptor.Descriptor[7]); + + usb_lld_reset (); + + /* Initialize Endpoint 0 */ + usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, + GNUK_MAX_PACKET_SIZE); + + for (i = 0; i < NUM_INTERFACES; i++) + gnuk_setup_endpoints_for_interface (i, 0); + + bDeviceState = ATTACHED; +} + +#define USB_CCID_REQ_ABORT 0x01 +#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02 +#define USB_CCID_REQ_GET_DATA_RATES 0x03 + +static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */ + +static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */ + +#if defined(PINPAD_DND_SUPPORT) +static const uint8_t lun_table[] = { 0, 0, 0, 0, }; +#endif + +static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, }; + +#define USB_FSIJ_GNUK_MEMINFO 0 +#define USB_FSIJ_GNUK_DOWNLOAD 1 +#define USB_FSIJ_GNUK_EXEC 2 + +static uint32_t rbit (uint32_t v) +{ + uint32_t r; + + asm ("rbit %0, %1" : "=r" (r) : "r" (v)); + return r; +} + +/* After calling this function, CRC module remain enabled. */ +static int download_check_crc32 (const uint32_t *end_p) +{ + uint32_t crc32 = *end_p; + const uint32_t *p; + + RCC->AHBENR |= RCC_AHBENR_CRCEN; + CRC->CR = CRC_CR_RESET; + + for (p = (const uint32_t *)&_regnual_start; p < end_p; p++) + CRC->DR = rbit (*p); + + if ((rbit (CRC->DR) ^ crc32) == 0xffffffff) + return USB_SUCCESS; + + return USB_UNSUPPORT; +} + +static int +gnuk_setup (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, uint16_t len) +{ + uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); + + if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)) + { + if (USB_SETUP_GET (req)) + { + if (req_no == USB_FSIJ_GNUK_MEMINFO) + { + usb_lld_set_data_to_send (mem_info, sizeof (mem_info)); + return USB_SUCCESS; + } + } + else /* SETUP_SET */ + { + uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index); + + if (req_no == USB_FSIJ_GNUK_DOWNLOAD) + { + if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED) + return USB_UNSUPPORT; + + if (addr < &_regnual_start || addr + len > &__heap_end__) + return USB_UNSUPPORT; + + if (index + len < 256) + memset (addr + index + len, 0, 256 - (index + len)); + + usb_lld_set_data_to_recv (addr, len); + return USB_SUCCESS; + } + else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0) + { + if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED) + return USB_UNSUPPORT; + + if (((uint32_t)addr & 0x03)) + return USB_UNSUPPORT; + + return download_check_crc32 ((uint32_t *)addr); + } + } + } + else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + if (index == 0) + { + if (USB_SETUP_GET (req)) + { + if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES) + { + usb_lld_set_data_to_send (freq_table, sizeof (freq_table)); + return USB_SUCCESS; + } + else if (req_no == USB_CCID_REQ_GET_DATA_RATES) + { + usb_lld_set_data_to_send (data_rate_table, + sizeof (data_rate_table)); + return USB_SUCCESS; + } + } + else + { + if (req_no == USB_CCID_REQ_ABORT) + /* wValue: bSeq, bSlot */ + /* Abortion is not supported in Gnuk */ + return USB_UNSUPPORT; + } + } +#ifdef ENABLE_VIRTUAL_COM_PORT + else if (index == 1) + return vcom_port_data_setup (req, req_no); +#endif +#ifdef PINPAD_DND_SUPPORT + else if (index == MSC_INTERFACE_NO) + { + if (USB_SETUP_GET (req)) + { + if (req_no == MSC_GET_MAX_LUN_COMMAND) + { + usb_lld_set_data_to_send (lun_table, sizeof (lun_table)); + return USB_SUCCESS; + } + } + else + if (req_no == MSC_MASS_STORAGE_RESET_COMMAND) + /* Should call resetting MSC thread, something like msc_reset() */ + return USB_SUCCESS; + } +#endif + + return USB_UNSUPPORT; +} + +static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, + uint16_t len) +{ + uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); + + if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) + && USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0) + { + if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED) + return; + + (void)value; (void)index; + usb_lld_prepare_shutdown (); /* No further USB communication */ + *icc_state_p = ICC_STATE_EXEC_REQUESTED; + } +} + + +static int +gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value) +{ + (void)index; + if (desc_type == DEVICE_DESCRIPTOR) + { + usb_lld_set_data_to_send (Device_Descriptor.Descriptor, + Device_Descriptor.Descriptor_Size); + return USB_SUCCESS; + } + else if (desc_type == CONFIG_DESCRIPTOR) + { + usb_lld_set_data_to_send (Config_Descriptor.Descriptor, + Config_Descriptor.Descriptor_Size); + return USB_SUCCESS; + } + else if (desc_type == STRING_DESCRIPTOR) + { + uint8_t desc_index = value & 0xff; + + if (desc_index < NUM_STRING_DESC) + { + usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor, + String_Descriptors[desc_index].Descriptor_Size); + return USB_SUCCESS; + } + } + + return USB_UNSUPPORT; +} + +static int gnuk_usb_event (uint8_t event_type, uint16_t value) +{ + int i; + uint8_t current_conf; + + switch (event_type) + { + case USB_EVENT_ADDRESS: + bDeviceState = ADDRESSED; + return USB_SUCCESS; + case USB_EVENT_CONFIG: + current_conf = usb_lld_current_configuration (); + if (current_conf == 0) + { + if (value != 1) + return USB_UNSUPPORT; + + usb_lld_set_configuration (value); + for (i = 0; i < NUM_INTERFACES; i++) + gnuk_setup_endpoints_for_interface (i, 0); + bDeviceState = CONFIGURED; + } + else if (current_conf != value) + { + if (value != 0) + return USB_UNSUPPORT; + + usb_lld_set_configuration (0); + for (i = 0; i < NUM_INTERFACES; i++) + gnuk_setup_endpoints_for_interface (i, 1); + bDeviceState = ADDRESSED; + } + /* Do nothing when current_conf == value */ + return USB_SUCCESS; + default: + break; + } + + return USB_UNSUPPORT; +} + +static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt) +{ + static uint8_t zero = 0; + + if (interface >= NUM_INTERFACES) + return USB_UNSUPPORT; + + switch (cmd) + { + case USB_SET_INTERFACE: + if (alt != 0) + return USB_UNSUPPORT; + else + { + gnuk_setup_endpoints_for_interface (interface, 0); + return USB_SUCCESS; + } + + case USB_GET_INTERFACE: + usb_lld_set_data_to_send (&zero, 1); + return USB_SUCCESS; + + default: + case USB_QUERY_INTERFACE: + return USB_SUCCESS; + } +} + +/* + * Interface to USB core + */ + +const struct usb_device_method Device_Method = { + gnuk_device_reset, + gnuk_ctrl_write_finish, + gnuk_setup, + gnuk_get_descriptor, + gnuk_usb_event, + gnuk_interface, +}; + +CH_IRQ_HANDLER (Vector90) +{ + CH_IRQ_PROLOGUE(); + chSysLockFromIsr(); + + usb_interrupt_handler (); + + chSysUnlockFromIsr(); + CH_IRQ_EPILOGUE(); +} diff --git a/src/usb_desc.c b/src/usb_desc.c index 47565e9..81b00b5 100644 --- a/src/usb_desc.c +++ b/src/usb_desc.c @@ -3,8 +3,11 @@ */ #include "config.h" -#include "usb_lib.h" -#include "usb_desc.h" +#include "ch.h" +#include "sys.h" +#include "usb_lld.h" +#include "usb_conf.h" +#include "usb-cdc.h" #define USB_ICC_INTERFACE_CLASS 0x0B #define USB_ICC_INTERFACE_SUBCLASS 0x00 @@ -15,28 +18,41 @@ static const uint8_t gnukDeviceDescriptor[] = { 18, /* bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x00, 0x02, /* bcdUSB = 2.00 */ + 0x10, 0x01, /* bcdUSB = 1.1 */ 0x00, /* bDeviceClass: 0 means deferred to interface */ 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ 0x40, /* bMaxPacketSize0 */ - 0x4b, 0x23, /* idVendor = 0x234b (FSIJ) */ - 0x00, 0x00, /* idProduct = 0x0000 (FSIJ USB Token) */ - 0x00, 0x02, /* bcdDevice = 2.00 */ +#include "usb-vid-pid-ver.c.inc" 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 */ }; +#define ICC_TOTAL_LENGTH (9+9+54+7+7) +#define ICC_NUM_INTERFACES 1 + #ifdef ENABLE_VIRTUAL_COM_PORT -#define W_TOTAL_LENGTH (9+9+54+7+7+9+5+5+4+5+7+9+7+7) -#define NUM_INTERFACES 3 /* two for CDC, one for GPG */ +#define VCOM_TOTAL_LENGTH (9+5+5+4+5+7+9+7+7) +#define VCOM_NUM_INTERFACES 2 #else -#define W_TOTAL_LENGTH (9+9+54+7+7) -#define NUM_INTERFACES 1 /* GPG only */ +#define VCOM_TOTAL_LENGTH 0 +#define VCOM_NUM_INTERFACES 0 #endif +#ifdef PINPAD_DND_SUPPORT +#define MSC_TOTAL_LENGTH (9+7+7) +#define MSC_NUM_INTERFACES 1 +#else +#define MSC_TOTAL_LENGTH 0 +#define MSC_NUM_INTERFACES 0 +#endif + +#define W_TOTAL_LENGTH (ICC_TOTAL_LENGTH+VCOM_TOTAL_LENGTH+MSC_TOTAL_LENGTH) +#define NUM_INTERFACES (ICC_NUM_INTERFACES+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES) + + /* Configuation Descriptor */ static const uint8_t gnukConfigDescriptor[] = { 9, /* bLength: Configuation Descriptor size */ @@ -86,8 +102,8 @@ static const uint8_t gnukConfigDescriptor[] = { * It is different now for better interaction to GPG's in-stock * ccid-driver. */ - 0x42, 0x08, 0x04, 0x00, /* dwFeatures (not ICCD): - * Short and extended APDU level: 0x40000 * + 0x42, 0x08, 0x02, 0x00, /* dwFeatures (not ICCD): + * Short APDU level : 0x20000 * * (what? means ICCD?) : 0x00800 * * Automatic IFSD : 0x00400 * NAD value other than 0x00 : 0x00200 @@ -100,12 +116,12 @@ static const uint8_t gnukConfigDescriptor[] = { * Auto activaction of ICC : 0x00004 * Automatic conf. based on ATR : 0x00002 g */ - 0x40, 0x01, 0, 0, /* dwMaxCCIDMessageLength */ + 0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 271 */ 0xff, /* bClassGetResponse: */ 0xff, /* bClassEnvelope: */ 0, 0, /* wLCDLayout: FIXED VALUE */ #if defined(PINPAD_SUPPORT) -#if defined(PINPAD_CIR_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DND_SUPPORT) 1, /* bPinSupport: with PIN pad (verify) */ #elif defined(PINPAD_DIAL_SUPPORT) 3, /* bPinSupport: with PIN pad (verify, modify) */ @@ -114,17 +130,17 @@ static const uint8_t gnukConfigDescriptor[] = { 0, /* bPinSupport: No PIN pad */ #endif 1, /* bMaxCCIDBusySlots: 1 */ - /*Endpoint 1 Descriptor*/ + /*Endpoint IN1 Descriptor*/ 7, /* bLength: Endpoint Descriptor size */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ 0x81, /* bEndpointAddress: (IN1) */ 0x02, /* bmAttributes: Bulk */ USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */ 0x00, /* bInterval */ - /*Endpoint 2 Descriptor*/ + /*Endpoint OUT1 Descriptor*/ 7, /* bLength: Endpoint Descriptor size */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ - 0x02, /* bEndpointAddress: (OUT2) */ + 0x01, /* bEndpointAddress: (OUT1) */ 0x02, /* bmAttributes: Bulk */ USB_ICC_DATA_SIZE, 0x00, /* wMaxPacketSize: */ 0x00, /* bInterval */ @@ -193,7 +209,40 @@ static const uint8_t gnukConfigDescriptor[] = { 0x83, /* bEndpointAddress: (IN3) */ 0x02, /* bmAttributes: Bulk */ VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */ - 0x00 /* bInterval */ + 0x00, /* bInterval */ +#endif +#ifdef PINPAD_DND_SUPPORT + /* Interface Descriptor.*/ + 9, /* bLength: Interface Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ +#ifdef ENABLE_VIRTUAL_COM_PORT + 0x03, /* bInterfaceNumber. */ +#else + 0x01, /* bInterfaceNumber. */ +#endif + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x08, /* bInterfaceClass (Mass Stprage). */ + 0x06, /* bInterfaceSubClass (SCSI + transparent command set, MSCO + chapter 2). */ + 0x50, /* bInterfaceProtocol (Bulk-Only + Mass Storage, MSCO chapter 3). */ + 0x00, /* iInterface. */ + /* Endpoint Descriptor.*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x86, /* bEndpointAddress: (IN6) */ + 0x02, /* bmAttributes (Bulk). */ + 0x40, 0x00, /* wMaxPacketSize. */ + 0x00, /* bInterval (ignored for bulk). */ + /* Endpoint Descriptor.*/ + 7, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x06, /* bEndpointAddress: (OUT6) */ + 0x02, /* bmAttributes (Bulk). */ + 0x40, 0x00, /* wMaxPacketSize. */ + 0x00, /* bInterval (ignored for bulk). */ #endif }; @@ -205,48 +254,36 @@ static const uint8_t gnukStringLangID[] = { 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[] = { - 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 -}; +#define USB_STRINGS_FOR_GNUK 1 +#include "usb-strings.c.inc" const uint8_t gnukStringSerial[] = { - 13*2+2, /* bLength */ + 19*2+2, /* bLength */ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ - '0', 0, '.', 0, '1', 0, '4', 0, /* Version number of Gnuk */ + /* FSIJ-1.0 */ + 'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0, + '1', 0, '.', 0, '0', 0, '.', 0, '1', 0, /* Version number of Gnuk */ '-', 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; - -const ONE_DESCRIPTOR Device_Descriptor = { - (uint8_t*)gnukDeviceDescriptor, +const struct Descriptor Device_Descriptor = { + gnukDeviceDescriptor, sizeof (gnukDeviceDescriptor) }; -const ONE_DESCRIPTOR Config_Descriptor = { - (uint8_t*)gnukConfigDescriptor, +const struct Descriptor Config_Descriptor = { + gnukConfigDescriptor, sizeof (gnukConfigDescriptor) }; -const ONE_DESCRIPTOR String_Descriptor[] = { - {(uint8_t*)gnukStringLangID, sizeof (gnukStringLangID)}, - {(uint8_t*)gnukStringVendor, sizeof (gnukStringVendor)}, - {(uint8_t*)gnukStringProduct, sizeof (gnukStringProduct)}, - {(uint8_t*)gnukStringSerial, sizeof (gnukStringSerial)}, +const struct Descriptor String_Descriptors[NUM_STRING_DESC] = { + {gnukStringLangID, sizeof (gnukStringLangID)}, + {gnukStringVendor, sizeof (gnukStringVendor)}, + {gnukStringProduct, sizeof (gnukStringProduct)}, + {gnukStringSerial, sizeof (gnukStringSerial)}, + {gnuk_revision_detail, sizeof (gnuk_revision_detail)}, + {gnuk_config_options, sizeof (gnuk_config_options)}, + {sys_version, sizeof (sys_version)}, }; diff --git a/src/usb_endp.c b/src/usb_endp.c deleted file mode 100644 index cdf675c..0000000 --- a/src/usb_endp.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Virtual COM port (for debug output only) - */ - -#include "usb_lib.h" - -#include "config.h" -#include "ch.h" -#include "gnuk.h" - -void -EP3_IN_Callback(void) -{ - if (stdout_thread) - chEvtSignalI (stdout_thread, EV_TX_READY); -} - -void -EP5_OUT_Callback(void) -{ - SetEPRxValid (ENDP3); -} diff --git a/src/usb_lld.c b/src/usb_lld.c index 9429712..df0c2f9 100644 --- a/src/usb_lld.c +++ b/src/usb_lld.c @@ -1,28 +1,1213 @@ +#ifdef FREE_STANDING +#include "types.h" +#else #include "ch.h" #include "hal.h" +#endif +#include "sys.h" #include "usb_lld.h" -extern void USB_Istr (void); +#define USB_MAX_PACKET_SIZE 64 /* For FS device */ -CH_IRQ_HANDLER (Vector90) { - CH_IRQ_PROLOGUE(); - chSysLockFromIsr(); +enum STANDARD_REQUESTS +{ + GET_STATUS = 0, + CLEAR_FEATURE, + RESERVED1, + SET_FEATURE, + RESERVED2, + SET_ADDRESS, + GET_DESCRIPTOR, + SET_DESCRIPTOR, + GET_CONFIGURATION, + SET_CONFIGURATION, + GET_INTERFACE, + SET_INTERFACE, + SYNCH_FRAME, + TOTAL_REQUEST /* Total number of Standard request */ +}; - USB_Istr(); +/* The state machine states of a control pipe */ +enum CONTROL_STATE +{ + WAIT_SETUP, + SETTING_UP, + IN_DATA, + OUT_DATA, + LAST_IN_DATA, + WAIT_STATUS_IN, + WAIT_STATUS_OUT, + STALLED, + PAUSE +}; - chSysUnlockFromIsr(); - CH_IRQ_EPILOGUE(); +enum FEATURE_SELECTOR +{ + ENDPOINT_STALL, + DEVICE_REMOTE_WAKEUP +}; + +struct DATA_INFO +{ + uint16_t len; + uint16_t offset; + uint8_t *addr; + uint8_t require_zlp; +}; + +struct CONTROL_INFO +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + +struct DEVICE_INFO +{ + uint8_t current_configuration; + uint8_t current_feature; + uint8_t state; +}; + +static struct CONTROL_INFO control_info; +static struct DEVICE_INFO device_info; +static struct DATA_INFO data_info; +extern const struct usb_device_method Device_Method; + +static struct CONTROL_INFO *const ctrl_p = &control_info; +static struct DEVICE_INFO *const dev_p = &device_info; +static struct DATA_INFO *const data_p = &data_info; +static const struct usb_device_method *const method_p = &Device_Method; + +#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */ +#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */ + +/* Control register */ +#define CNTR ((__IO uint16_t *)(REG_BASE + 0x40)) +/* Interrupt status register */ +#define ISTR ((__IO uint16_t *)(REG_BASE + 0x44)) +/* Frame number register */ +#define FNR ((__IO uint16_t *)(REG_BASE + 0x48)) +/* Device address register */ +#define DADDR ((__IO uint16_t *)(REG_BASE + 0x4C)) +/* Buffer Table address register */ +#define BTABLE ((__IO uint16_t *)(REG_BASE + 0x50)) + +#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ +#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ +#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ +#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ +#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ +#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ +#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ +#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ + +#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ +#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ + +#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ +#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ +#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ +#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ +#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ +#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ +#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ +#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ + +#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ +#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ +#define CNTR_ERRM (0x2000) /* ERRor Mask */ +#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ +#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ +#define CNTR_RESETM (0x0400) /* RESET Mask */ +#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ +#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ + +#define CNTR_RESUME (0x0010) /* RESUME request */ +#define CNTR_FSUSP (0x0008) /* Force SUSPend */ +#define CNTR_LPMODE (0x0004) /* Low-power MODE */ +#define CNTR_PDWN (0x0002) /* Power DoWN */ +#define CNTR_FRES (0x0001) /* Force USB RESet */ + +#define DADDR_EF (0x80) +#define DADDR_ADD (0x7F) + +#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ +#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ +#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ +#define EP_SETUP (0x0800) /* EndPoint SETUP */ +#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ +#define EP_KIND (0x0100) /* EndPoint KIND */ +#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ +#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ +#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ +#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ + +#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) + +/* STAT_TX[1:0] STATus for TX transfer */ +#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ +#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ +#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ +#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ +#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ +#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ + +/* STAT_RX[1:0] STATus for RX transfer */ +#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ +#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ +#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ +#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ +#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ + +static void usb_handle_transfer (void); + +static void st103_set_btable (void) +{ + *BTABLE = 0; } -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 IRQ(s): - * USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous) - * USBWakeUp_IRQn (suspend/resume) - */ - RCC->APB1RSTR = RCC_APB1RSTR_USBRST; - RCC->APB1RSTR = 0; +static uint16_t st103_get_istr (void) +{ + return *ISTR; +} + +static void st103_set_istr (uint16_t istr) +{ + *ISTR = istr; +} + +static void st103_set_cntr (uint16_t cntr) +{ + *CNTR = cntr; +} + +static void st103_set_daddr (uint16_t daddr) +{ + *DADDR = daddr | DADDR_EF; +} + +static void st103_set_epreg (uint8_t ep_num, uint16_t value) +{ + uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4); + + *reg_p = value; +} + +static uint16_t st103_get_epreg (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4); + + return *reg_p; +} + +static void st103_set_tx_addr (uint8_t ep_num, uint16_t addr) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2); + + *reg_p = addr; +} + +static uint16_t st103_get_tx_addr (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2); + + return *reg_p; +} + + +static void st103_set_tx_count (uint8_t ep_num, uint16_t size) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2); + + *reg_p = size; +} + +static uint16_t st103_get_tx_count (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2); + + return *reg_p & 0x03ff; +} + + +static void st103_set_rx_addr (uint8_t ep_num, uint16_t addr) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2); + + *reg_p = addr; +} + +static uint16_t st103_get_rx_addr (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2); + + return *reg_p; +} + + +static void st103_set_rx_buf_size (uint8_t ep_num, uint16_t size) +{ /* Assume size is even */ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2); + uint16_t value; + + if (size <= 62) + value = (size & 0x3e) << 9; + else + value = 0x8000 | (((size >> 5) - 1) << 10); + + *reg_p = value; +} + +static uint16_t st103_get_rx_count (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2); + + return *reg_p & 0x03ff; +} + + +static void st103_ep_clear_ctr_rx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_RX & EPREG_MASK; + + st103_set_epreg (ep_num, value); +} + +static void st103_ep_clear_ctr_tx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_TX & EPREG_MASK; + + st103_set_epreg (ep_num, value); +} + +static void st103_ep_set_rxtx_status (uint8_t ep_num, uint16_t st_rx, + uint16_t st_tx) +{ + uint16_t value = st103_get_epreg (ep_num); + + value &= (EPREG_MASK|EPRX_STAT|EPTX_STAT); + value ^= (EPRX_DTOG1 & st_rx); + value ^= (EPRX_DTOG2 & st_rx); + value ^= (EPTX_DTOG1 & st_tx); + value ^= (EPTX_DTOG2 & st_tx); + value |= EP_CTR_RX | EP_CTR_TX; + st103_set_epreg (ep_num, value); +} + +static void st103_ep_set_rx_status (uint8_t ep_num, uint16_t st_rx) +{ + uint16_t value = st103_get_epreg (ep_num); + + value &= (EPREG_MASK|EPRX_STAT); + value ^= (EPRX_DTOG1 & st_rx); + value ^= (EPRX_DTOG2 & st_rx); + value |= EP_CTR_RX | EP_CTR_TX; + st103_set_epreg (ep_num, value); +} + +static uint16_t st103_ep_get_rx_status (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + return value & EPRX_STAT; +} + +static void st103_ep_set_tx_status (uint8_t ep_num, uint16_t st_tx) +{ + uint16_t value = st103_get_epreg (ep_num); + + value &= (EPREG_MASK|EPTX_STAT); + value ^= (EPTX_DTOG1 & st_tx); + value ^= (EPTX_DTOG2 & st_tx); + value |= EP_CTR_RX | EP_CTR_TX; + st103_set_epreg (ep_num, value); +} + +static uint16_t st103_ep_get_tx_status (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + return value & EPTX_STAT; +} + +static void st103_ep_clear_dtog_rx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + if ((value & EP_DTOG_RX)) + { + value &= EPREG_MASK; + value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_RX; + st103_set_epreg (ep_num, value); + } +} + +static void st103_ep_clear_dtog_tx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + if ((value & EP_DTOG_TX)) + { + value &= EPREG_MASK; + value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX; + st103_set_epreg (ep_num, value); + } +} + +void usb_lld_init (uint8_t feature) +{ + usb_lld_sys_init (); + + dev_p->state = IN_DATA; + + usb_lld_set_configuration (0); + usb_lld_set_feature (feature); + + /* Reset USB */ + st103_set_cntr (CNTR_FRES); + st103_set_cntr (0); + + /* Clear Interrupt Status Register, and enable interrupt for USB */ + st103_set_istr (0); + st103_set_cntr (CNTR_CTRM | CNTR_RESETM); +} + +void usb_lld_prepare_shutdown (void) +{ + st103_set_istr (0); + st103_set_cntr (0); +} + +void usb_lld_shutdown (void) +{ + st103_set_cntr (CNTR_PDWN); + usb_lld_sys_shutdown (); +} + +void +usb_interrupt_handler (void) +{ + uint16_t istr_value = st103_get_istr (); + + if (istr_value & ISTR_CTR) + usb_handle_transfer (); + + if (istr_value & ISTR_RESET) + { + st103_set_istr (CLR_RESET); + method_p->reset (); + } + + if (istr_value & ISTR_DOVR) + st103_set_istr (CLR_DOVR); + + if (istr_value & ISTR_ERR) + st103_set_istr (CLR_ERR); +} + +static void handle_datastage_out (void) +{ + if (data_p->addr && data_p->len) + { + uint8_t *buf; + uint32_t len = st103_get_rx_count (ENDP0); + + if (len > data_p->len) + len = data_p->len; + + buf = data_p->addr + data_p->offset; + usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len); + data_p->len -= len; + data_p->offset += len; + } + + if (data_p->len == 0) + { + dev_p->state = WAIT_STATUS_IN; + st103_set_tx_count (ENDP0, 0); + st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID); + } + else + { + dev_p->state = OUT_DATA; + st103_ep_set_rx_status (ENDP0, EP_RX_VALID); + } +} + +static void handle_datastage_in (void) +{ + uint32_t len = USB_MAX_PACKET_SIZE;; + const uint8_t *buf; + + if ((data_p->len == 0) && (dev_p->state == LAST_IN_DATA)) + { + if (data_p->require_zlp == TRUE) + { + data_p->require_zlp = FALSE; + + /* No more data to send. Send empty packet */ + st103_set_tx_count (ENDP0, 0); + st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID); + } + else + { + /* No more data to send, proceed to receive OUT acknowledge.*/ + dev_p->state = WAIT_STATUS_OUT; + st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_STALL); + } + + return; + } + + dev_p->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA; + + if (len > data_p->len) + len = data_p->len; + + buf = (const uint8_t *)data_p->addr + data_p->offset; + usb_lld_to_pmabuf (buf, st103_get_tx_addr (ENDP0), len); + data_p->len -= len; + data_p->offset += len; + st103_set_tx_count (ENDP0, len); + st103_ep_set_tx_status (ENDP0, EP_TX_VALID); +} + +typedef int (*HANDLER) (uint8_t req, + uint16_t value, uint16_t index, uint16_t length); + +static int std_none (uint8_t req, + uint16_t value, uint16_t index, uint16_t length) +{ + (void)req; (void)value; (void)index; (void)length; + return USB_UNSUPPORT; +} + +static int std_get_status (uint8_t req, + uint16_t value, uint16_t index, uint16_t length) +{ + static uint16_t status_info; + uint8_t rcp = req & RECIPIENT; + + status_info = 0; /* Reset Status Information */ + data_p->addr = (uint8_t *)&status_info; + + if (value != 0 || length != 2 || (index >> 8) != 0 + || (req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (index == 0) + { + /* Get Device Status */ + uint8_t feature = dev_p->current_feature; + + /* Remote Wakeup enabled */ + if ((feature & (1 << 5))) + status_info |= 2; + else + status_info &= ~2; + + /* Bus-powered */ + if ((feature & (1 << 6))) + status_info |= 1; + else /* Self-powered */ + status_info &= ~1; + + data_p->len = 2; + return USB_SUCCESS; + } + } + else if (rcp == INTERFACE_RECIPIENT) + { + int r; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + r = (*method_p->interface) (USB_QUERY_INTERFACE, index, 0); + if (r != USB_SUCCESS) + return USB_UNSUPPORT; + + data_p->len = 2; + return USB_SUCCESS; + } + else if (rcp == ENDPOINT_RECIPIENT) + { + uint8_t endpoint = (index & 0x0f); + uint16_t status; + + if ((index & 0x70) != 0 || endpoint == ENDP0) + return USB_UNSUPPORT; + + if ((index & 0x80)) + { + status = st103_ep_get_tx_status (endpoint); + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + else if (status == EP_TX_STALL) + status_info |= 1; /* IN Endpoint stalled */ + } + else + { + status = st103_ep_get_rx_status (endpoint); + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + else if (status == EP_RX_STALL) + status_info |= 1; /* OUT Endpoint stalled */ + } + + data_p->len = 2; + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_clear_feature (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (length != 0 || index != 0) + return USB_UNSUPPORT; + + if (value == DEVICE_REMOTE_WAKEUP) + { + dev_p->current_feature &= ~(1 << 5); + return USB_SUCCESS; + } + } + else if (rcp == ENDPOINT_RECIPIENT) + { + uint8_t endpoint = (index & 0x0f); + uint16_t status; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + if (length != 0 || (index >> 8) != 0 || value != ENDPOINT_STALL + || endpoint == ENDP0) + return USB_UNSUPPORT; + + if ((index & 0x80)) + status = st103_ep_get_tx_status (endpoint); + else + status = st103_ep_get_rx_status (endpoint); + + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + + if (index & 0x80) /* IN endpoint */ + st103_ep_clear_dtog_tx (endpoint); + else /* OUT endpoint */ + st103_ep_clear_dtog_rx (endpoint); + + // event?? + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_set_feature (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (length != 0 || index != 0) + return USB_UNSUPPORT; + + if (value == DEVICE_REMOTE_WAKEUP) + { + dev_p->current_feature |= 1 << 5; + // event?? + return USB_SUCCESS; + } + } + else if (rcp == ENDPOINT_RECIPIENT) + { + uint8_t endpoint = (index & 0x0f); + uint32_t status; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + if (length != 0 || (index >> 8) != 0 || value != 0 || endpoint == ENDP0) + return USB_UNSUPPORT; + + if ((index & 0x80)) + status = st103_ep_get_tx_status (endpoint); + else + status = st103_ep_get_rx_status (endpoint); + + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + + if (index & 0x80) + /* IN endpoint */ + st103_ep_set_tx_status (endpoint, EP_TX_STALL); + else + /* OUT endpoint */ + st103_ep_set_rx_status (endpoint, EP_RX_STALL); + + // event?? + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_set_address (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (length == 0 && value <= 127 && index == 0 + && dev_p->current_configuration == 0) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_get_descriptor (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + (void)length; + if (rcp == DEVICE_RECIPIENT) + return (*method_p->get_descriptor) ((value >> 8), index, value); + + return USB_UNSUPPORT; +} + +static int std_get_configuration (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + (void)value; (void)index; (void)length; + if (rcp == DEVICE_RECIPIENT) + { + data_p->addr = &dev_p->current_configuration; + data_p->len = 1; + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_set_configuration (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0) + { + int r; + + r = (*method_p->event) (USB_EVENT_CONFIG, value); + if (r == USB_SUCCESS) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_get_interface (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + if (rcp == INTERFACE_RECIPIENT) + { + if (value != 0 || (index >> 8) != 0 || length != 1) + return USB_UNSUPPORT; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + return (*method_p->interface) (USB_GET_INTERFACE, index, 0); + } + + return USB_UNSUPPORT; +} + +static int std_set_interface (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == INTERFACE_RECIPIENT) + { + int r; + + if (length != 0 || (index >> 8) != 0 || (value >> 8) != 0) + return USB_UNSUPPORT; + + if (dev_p->current_configuration != 0) + return USB_UNSUPPORT; + + r = (*method_p->interface) (USB_SET_INTERFACE, index, value); + if (r == USB_SUCCESS) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static const HANDLER std_request_handler[TOTAL_REQUEST] = { + std_get_status, + std_clear_feature, + std_none, + std_set_feature, + std_none, + std_set_address, + std_get_descriptor, + std_none, /* set_descriptor is not supported */ + std_get_configuration, + std_set_configuration, + std_get_interface, + std_set_interface, + std_none, /* sync_frame is not supported (for now) */ +}; + +static void handle_setup0 (void) +{ + const uint16_t *pw; + uint16_t w; + uint8_t req; + int r = USB_UNSUPPORT; + HANDLER handler; + + pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2)); + w = *pw++; + + ctrl_p->bmRequestType = w & 0xff; + ctrl_p->bRequest = req = w >> 8; + pw++; + ctrl_p->wValue = *pw++; + pw++; + ctrl_p->wIndex = *pw++; + pw++; + ctrl_p->wLength = *pw; + + data_p->addr = NULL; + data_p->len = 0; + data_p->offset = 0; + + if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST) + { + if (req < TOTAL_REQUEST) + { + handler = std_request_handler[req]; + r = (*handler) (ctrl_p->bmRequestType, + ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength); + } + } + else + r = (*method_p->setup) (ctrl_p->bmRequestType, req, + ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength); + + if (r != USB_SUCCESS) + dev_p->state = STALLED; + else + { + if (USB_SETUP_GET (ctrl_p->bmRequestType)) + { + uint32_t len = ctrl_p->wLength; + + /* Restrict the data length to be the one host asks for */ + if (data_p->len > len) + data_p->len = len; + + if ((data_p->len % USB_MAX_PACKET_SIZE) == 0) + data_p->require_zlp = TRUE; + else + data_p->require_zlp = FALSE; + + dev_p->state = IN_DATA; + handle_datastage_in (); + } + else if (ctrl_p->wLength == 0) + { + dev_p->state = WAIT_STATUS_IN; + st103_set_tx_count (ENDP0, 0); + st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID); + } + else + { + dev_p->state = OUT_DATA; + st103_ep_set_rx_status (ENDP0, EP_RX_VALID); + } + } +} + +static void handle_in0 (void) +{ + if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA) + handle_datastage_in (); + else if (dev_p->state == WAIT_STATUS_IN) + { + if ((ctrl_p->bRequest == SET_ADDRESS) && + ((ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT)) + == (STANDARD_REQUEST | DEVICE_RECIPIENT))) + { + st103_set_daddr (ctrl_p->wValue); + (*method_p->event) (USB_EVENT_ADDRESS, ctrl_p->wValue); + } + else + (*method_p->ctrl_write_finish) (ctrl_p->bmRequestType, + ctrl_p->bRequest, ctrl_p->wValue, + ctrl_p->wIndex, ctrl_p->wLength); + + dev_p->state = STALLED; + } + else + dev_p->state = STALLED; +} + +static void handle_out0 (void) +{ + if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA) + /* host aborts the transfer before finish */ + dev_p->state = STALLED; + else if (dev_p->state == OUT_DATA) + handle_datastage_out (); + else if (dev_p->state == WAIT_STATUS_OUT) + dev_p->state = STALLED; + /* Unexpect state, STALL the endpoint */ + else + dev_p->state = STALLED; +} + +static void nop_proc (void) +{ +} + +#define WEAK __attribute__ ((weak, alias ("nop_proc"))) +void WEAK EP1_IN_Callback (void); +void WEAK EP2_IN_Callback (void); +void WEAK EP3_IN_Callback (void); +void WEAK EP4_IN_Callback (void); +void WEAK EP5_IN_Callback (void); +void WEAK EP6_IN_Callback (void); +void WEAK EP7_IN_Callback (void); + +void WEAK EP1_OUT_Callback (void); +void WEAK EP2_OUT_Callback (void); +void WEAK EP3_OUT_Callback (void); +void WEAK EP4_OUT_Callback (void); +void WEAK EP5_OUT_Callback (void); +void WEAK EP6_OUT_Callback (void); +void WEAK EP7_OUT_Callback (void); + +void (*const ep_intr_handler_IN[7]) (void) = { + EP1_IN_Callback, + EP2_IN_Callback, + EP3_IN_Callback, + EP4_IN_Callback, + EP5_IN_Callback, + EP6_IN_Callback, + EP7_IN_Callback, +}; + +void (*const ep_intr_handler_OUT[7]) (void) = { + EP1_OUT_Callback, + EP2_OUT_Callback, + EP3_OUT_Callback, + EP4_OUT_Callback, + EP5_OUT_Callback, + EP6_OUT_Callback, + EP7_OUT_Callback, +}; + +static void +usb_handle_transfer (void) +{ + uint16_t ep_value = 0; + uint16_t istr_value; + uint8_t ep_index; + + while (((istr_value = st103_get_istr ()) & ISTR_CTR) != 0) + { + ep_index = (istr_value & ISTR_EP_ID); + if (ep_index == 0) + { + if ((istr_value & ISTR_DIR) == 0) + { /* DIR = 0 */ + /* DIR = 0 => IN int */ + /* DIR = 0 implies that (EP_CTR_TX = 1) always */ + + st103_ep_clear_ctr_tx (ENDP0); + handle_in0 (); + } + else + { /* DIR = 1 */ + /* DIR = 1 & CTR_RX => SETUP or OUT int */ + /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ + + ep_value = st103_get_epreg (ENDP0); + if ((ep_value & EP_SETUP) != 0) + { + st103_ep_clear_ctr_rx (ENDP0); + handle_setup0 (); + } + else if ((ep_value & EP_CTR_RX) != 0) + { + st103_ep_clear_ctr_rx (ENDP0); + handle_out0 (); + } + } + + if (dev_p->state == STALLED) + st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL); + } + else + { + /* Decode and service non control endpoints interrupt */ + /* process related endpoint register */ + ep_value = st103_get_epreg (ep_index); + + if ((ep_value & EP_CTR_RX) != 0) + { + st103_ep_clear_ctr_rx (ep_index); + (*ep_intr_handler_OUT[ep_index-1]) (); + } + + if ((ep_value & EP_CTR_TX) != 0) + { + st103_ep_clear_ctr_tx (ep_index); + (*ep_intr_handler_IN[ep_index-1]) (); + } + } + } +} + +void usb_lld_reset (void) +{ + st103_set_btable (); + st103_set_daddr (0); +} + +void usb_lld_txcpy (const void *src, + int ep_num, int offset, size_t len) +{ + usb_lld_to_pmabuf (src, st103_get_tx_addr (ep_num) + offset, len); +} + +void usb_lld_write (uint8_t ep_num, const void *buf, size_t len) +{ + usb_lld_to_pmabuf (buf, st103_get_tx_addr (ep_num), len); + st103_set_tx_count (ep_num, len); + st103_ep_set_tx_status (ep_num, EP_TX_VALID); +} + +void usb_lld_rxcpy (uint8_t *dst, + int ep_num, int offset, size_t len) +{ + usb_lld_from_pmabuf (dst, st103_get_rx_addr (ep_num) + offset, len); +} + +void usb_lld_tx_enable (int ep_num, size_t len) +{ + st103_set_tx_count (ep_num, len); + st103_ep_set_tx_status (ep_num, EP_TX_VALID); +} + +int usb_lld_tx_data_len (int ep_num) +{ + return st103_get_tx_count (ep_num); +} + +int usb_lld_rx_data_len (int ep_num) +{ + return st103_get_rx_count (ep_num); +} + +void usb_lld_stall_tx (int ep_num) +{ + st103_ep_set_tx_status (ep_num, EP_TX_STALL); +} + +void usb_lld_stall_rx (int ep_num) +{ + st103_ep_set_rx_status (ep_num, EP_RX_STALL); +} + +void usb_lld_rx_enable (int ep_num) +{ + st103_ep_set_rx_status (ep_num, EP_RX_VALID); +} + +void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind, + int ep_rx_addr, int ep_tx_addr, + int ep_rx_buf_size) +{ + uint16_t epreg_value = st103_get_epreg (ep_num); + uint16_t ep_rxtx_status = 0; /* Both disabled */ + + /* Clear: Write 1 if 1: EP_DTOG_RX, EP_DTOG_TX */ + /* Set: Write: EP_T_FIELD, EP_KIND, EPADDR_FIELD */ + /* Set: Toggle: EPRX_STAT, EPTX_STAT */ + epreg_value &= (EPRX_STAT | EP_SETUP | EPTX_STAT | EP_DTOG_RX | EP_DTOG_TX); +#if USB_KEEP_CORRECT_TRANSFER_FLAGS + /* Keep: Write 1: EP_CTR_RX, EP_CTR_TX */ + epreg_value |= (EP_CTR_RX|EP_CTR_TX); +#else + /* Clear: Write 0: EP_CTR_RX, EP_CTR_TX */ +#endif + epreg_value |= ep_type; + epreg_value |= ep_kind; + epreg_value |= ep_num; + + if (ep_rx_addr) + { + ep_rxtx_status |= EP_RX_VALID; + st103_set_rx_addr (ep_num, ep_rx_addr); + st103_set_rx_buf_size (ep_num, ep_rx_buf_size); + } + + if (ep_tx_addr) + { + ep_rxtx_status |= EP_TX_NAK; + st103_set_tx_addr (ep_num, ep_tx_addr); + } + + epreg_value ^= (EPRX_DTOG1 & ep_rxtx_status); + epreg_value ^= (EPRX_DTOG2 & ep_rxtx_status); + epreg_value ^= (EPTX_DTOG1 & ep_rxtx_status); + epreg_value ^= (EPTX_DTOG2 & ep_rxtx_status); + + st103_set_epreg (ep_num, epreg_value); +} + +void usb_lld_set_configuration (uint8_t config) +{ + dev_p->current_configuration = config; +} + +uint8_t usb_lld_current_configuration (void) +{ + return dev_p->current_configuration; +} + +void usb_lld_set_feature (uint8_t feature) +{ + dev_p->current_feature = feature; +} + +void usb_lld_set_data_to_send (const void *p, size_t len) +{ + data_p->addr = (uint8_t *)p; + data_p->len = len; +} + +void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n) +{ + const uint8_t *s = (const uint8_t *)src; + uint16_t *p; + uint16_t w; + + if (n == 0) + return; + + if ((addr & 1)) + { + p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2); + w = *p; + w = (w & 0xff) | (*s++) << 8; + *p = w; + p += 2; + n--; + } + else + p = (uint16_t *)(PMA_ADDR + addr * 2); + + while (n >= 2) + { + w = *s++; + w |= (*s++) << 8; + *p = w; + p += 2; + n -= 2; + } + + if (n > 0) + { + w = *s; + *p = w; + } +} + +void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n) +{ + uint8_t *d = (uint8_t *)dst; + uint16_t *p; + uint16_t w; + + if (n == 0) + return; + + if ((addr & 1)) + { + p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2); + w = *p; + *d++ = (w >> 8); + p += 2; + n--; + } + else + p = (uint16_t *)(PMA_ADDR + addr * 2); + + while (n >= 2) + { + w = *p; + *d++ = (w & 0xff); + *d++ = (w >> 8); + p += 2; + n -= 2; + } + + if (n > 0) + { + w = *p; + *d = (w & 0xff); + } } diff --git a/src/usb_lld.h b/src/usb_lld.h index 9e0ecfd..481c7a7 100644 --- a/src/usb_lld.h +++ b/src/usb_lld.h @@ -1,2 +1,158 @@ +#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define USB_STRING_DESCRIPTOR_TYPE 0x03 +#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 + +#define STANDARD_ENDPOINT_DESC_SIZE 0x09 + +/* endpoints enumeration */ +#define ENDP0 ((uint8_t)0) +#define ENDP1 ((uint8_t)1) +#define ENDP2 ((uint8_t)2) +#define ENDP3 ((uint8_t)3) +#define ENDP4 ((uint8_t)4) +#define ENDP5 ((uint8_t)5) +#define ENDP6 ((uint8_t)6) +#define ENDP7 ((uint8_t)7) + +/* EP_TYPE[1:0] EndPoint TYPE */ +#define EP_BULK (0x0000) /* EndPoint BULK */ +#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ +#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ +#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ + +enum RECIPIENT_TYPE +{ + DEVICE_RECIPIENT, /* Recipient device */ + INTERFACE_RECIPIENT, /* Recipient interface */ + ENDPOINT_RECIPIENT, /* Recipient endpoint */ + OTHER_RECIPIENT +}; + +enum DESCRIPTOR_TYPE +{ + DEVICE_DESCRIPTOR = 1, + CONFIG_DESCRIPTOR, + STRING_DESCRIPTOR, + INTERFACE_DESCRIPTOR, + ENDPOINT_DESCRIPTOR +}; + +#define REQUEST_DIR 0x80 /* Mask to get request dir */ +#define REQUEST_TYPE 0x60 /* Mask to get request type */ +#define STANDARD_REQUEST 0x00 /* Standard request */ +#define CLASS_REQUEST 0x20 /* Class request */ +#define VENDOR_REQUEST 0x40 /* Vendor request */ +#define RECIPIENT 0x1F /* Mask to get recipient */ + +#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0) +#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0) + +struct Descriptor +{ + const uint8_t *Descriptor; + uint16_t Descriptor_Size; +}; + +enum +{ + USB_UNSUPPORT = 0, + USB_SUCCESS = 1, +}; + +struct usb_device_method +{ + void (*reset) (void); + void (*ctrl_write_finish) (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, uint16_t len); + int (*setup) (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, uint16_t len); + int (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value); + int (*event) (uint8_t event_type, uint16_t value); + int (*interface) (uint8_t cmd, uint16_t interface, uint16_t value); +}; + +enum { + USB_EVENT_ADDRESS, + USB_EVENT_CONFIG, + USB_EVENT_SUSPEND, + USB_EVENT_WAKEUP, + USB_EVENT_STALL, +}; + +enum { + USB_SET_INTERFACE, + USB_GET_INTERFACE, + USB_QUERY_INTERFACE, +}; + +extern void USB_Cable_Config (int NewState); + +extern const struct usb_device_method Device_Method; + +extern const struct Descriptor Device_Descriptor; +extern const struct Descriptor Config_Descriptor; +extern const struct Descriptor String_Descriptors[]; + +enum DEVICE_STATE +{ + UNCONNECTED, + ATTACHED, + POWERED, + SUSPENDED, + ADDRESSED, + CONFIGURED +}; + +extern uint32_t bDeviceState; + #define STM32_USB_IRQ_PRIORITY 11 -void usb_lld_init (void); + +extern void usb_lld_init (uint8_t feature); + +extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n); + +extern void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n); + +extern void usb_lld_stall_tx (int ep_num); + +extern void usb_lld_stall_rx (int ep_num); + +extern int usb_lld_tx_data_len (int ep_num); + +extern void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len); + +extern void usb_lld_tx_enable (int ep_num, size_t len); + +extern void usb_lld_write (uint8_t ep_num, const void *buf, size_t len); + +extern void usb_lld_rx_enable (int ep_num); + +extern int usb_lld_rx_data_len (int ep_num); + +extern void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len); + +extern void usb_lld_reset (void); + +extern void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind, + int ep_rx_addr, int ep_tx_addr, + int ep_rx_memory_size); + +extern void usb_lld_set_configuration (uint8_t config); + +extern uint8_t usb_lld_current_configuration (void); + +extern void usb_lld_set_feature (uint8_t feature); + +extern void usb_lld_set_data_to_send (const void *p, size_t len); + +extern inline void usb_lld_set_data_to_recv (void *p, size_t len) +{ + usb_lld_set_data_to_send ((const void *)p, len); +} + +extern void usb_lld_prepare_shutdown (void); +extern void usb_lld_shutdown (void); + +extern void usb_interrupt_handler (void); diff --git a/src/usb_prop.c b/src/usb_prop.c deleted file mode 100644 index 1abef3e..0000000 --- a/src/usb_prop.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * usb_prop.c - glue/interface code between Gnuk and USB-FS-Device_Lib - * - * Copyright (C) 2010, 2011 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 . - * - */ - -/* Packet size of USB Bulk transfer for full speed */ -#define GNUK_MAX_PACKET_SIZE 64 - -#include "config.h" -#include "usb_lib.h" -#include "usb_conf.h" -#include "usb_prop.h" -#include "usb_desc.h" -#include "usb_pwr.h" -#include "hw_config.h" - -#ifdef ENABLE_VIRTUAL_COM_PORT -#include "usb-cdc-vport.c" -#endif - - -static void -gnuk_device_init (void) -{ - 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 DEVICE as not configured */ - pInformation->Current_Configuration = 0; - - /* Current Feature initialization */ - pInformation->Current_Feature = Config_Descriptor.Descriptor[7]; - - /* Set 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_BULK); - SetEPRxAddr (ENDP2, ENDP2_RXADDR); - SetEPRxCount (ENDP2, GNUK_MAX_PACKET_SIZE); - SetEPRxStatus (ENDP2, EP_RX_VALID); - SetEPTxStatus (ENDP2, EP_TX_DIS); - -#ifdef ENABLE_VIRTUAL_COM_PORT - /* Initialize Endpoint 3 */ - SetEPType (ENDP3, EP_BULK); - SetEPTxAddr (ENDP3, ENDP3_TXADDR); - SetEPTxStatus (ENDP3, EP_TX_NAK); - SetEPRxStatus (ENDP3, EP_RX_DIS); - - /* Initialize Endpoint 4 */ - SetEPType (ENDP4, EP_INTERRUPT); - 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); - SetEPRxStatus (ENDP5, EP_RX_VALID); - SetEPTxStatus (ENDP5, EP_TX_DIS); -#endif - - /* 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_SetInterface (void) -{ - uint16_t intf = pInformation->USBwIndex0; - - /* alternateSetting: pInformation->USBwValue0 should be 0 */ - - if (intf == 0) - { - ClearDTOG_RX (ENDP2); - ClearDTOG_TX (ENDP1); - } -#ifdef ENABLE_VIRTUAL_COM_PORT - else if (intf == 1) - { - ClearDTOG_TX (ENDP4); - } - else if (intf == 2) - { - ClearDTOG_RX (ENDP5); - ClearDTOG_TX (ENDP3); - } -#endif -} - -static void -gnuk_device_SetDeviceAddress (void) -{ - bDeviceState = ADDRESSED; -} - -/* IN from port 0 */ -static void -gnuk_device_Status_In (void) -{ -} - -/* OUT to port 0 */ -static void -gnuk_device_Status_Out (void) -{ -} - -static uint8_t * -gnuk_device_GetDeviceDescriptor (uint16_t Length) -{ - return Standard_GetDescriptorData (Length, - (PONE_DESCRIPTOR)&Device_Descriptor); -} - -static uint8_t * -gnuk_device_GetConfigDescriptor (uint16_t Length) -{ - return Standard_GetDescriptorData (Length, - (PONE_DESCRIPTOR)&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, - (PONE_DESCRIPTOR)&String_Descriptor[wValue0]); -} - -#ifdef ENABLE_VIRTUAL_COM_PORT -#define NUM_INTERFACES 3 /* two for CDC, one for CCID */ -#else -#define NUM_INTERFACES 1 /* CCID only */ -#endif - -static RESULT -gnuk_device_Get_Interface_Setting (uint8_t Interface, uint8_t AlternateSetting) -{ - if (AlternateSetting > 0) /* Any interface, we have no alternate */ - return USB_UNSUPPORT; - else if (Interface > NUM_INTERFACES) - return USB_UNSUPPORT; - - return USB_SUCCESS; -} - -#define USB_CCID_REQ_ABORT 0x01 -#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02 -#define USB_CCID_REQ_GET_DATA_RATES 0x03 - -static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */ -static uint8_t * -gnuk_clock_frequencies (uint16_t len) -{ - if (len == 0) - { - pInformation->Ctrl_Info.Usb_wLength = sizeof (freq_table); - return NULL; - } - - return (uint8_t *)freq_table; -} - -static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */ -static uint8_t * -gnuk_data_rates (uint16_t len) -{ - if (len == 0) - { - pInformation->Ctrl_Info.Usb_wLength = sizeof (data_rate_table); - return NULL; - } - - return (uint8_t *)data_rate_table; -} - -static RESULT -gnuk_setup_with_data (uint8_t RequestNo) -{ - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) - if (pInformation->USBwIndex0 == 0) /* Interface */ - { - if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES) - { - pInformation->Ctrl_Info.CopyData = gnuk_clock_frequencies; - pInformation->Ctrl_Info.Usb_wOffset = 0; - gnuk_clock_frequencies (0); - return USB_SUCCESS; - } - else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES) - { - pInformation->Ctrl_Info.CopyData = gnuk_data_rates; - pInformation->Ctrl_Info.Usb_wOffset = 0; - gnuk_data_rates (0); - return USB_SUCCESS; - } - else - return USB_UNSUPPORT; - } - else - { -#if defined(ENABLE_VIRTUAL_COM_PORT) - return Virtual_Com_Port_Data_Setup (RequestNo); -#else - return USB_UNSUPPORT; -#endif - } - else - return USB_UNSUPPORT; -} - -static RESULT -gnuk_setup_with_nodata (uint8_t RequestNo) -{ - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) - if (pInformation->USBwIndex0 == 0) /* Interface */ - { - if (RequestNo == USB_CCID_REQ_ABORT) - /* wValue: bSeq, bSlot */ - /* Abortion is not supported in Gnuk */ - return USB_UNSUPPORT; - else - return USB_UNSUPPORT; - } - else - { -#if defined(ENABLE_VIRTUAL_COM_PORT) - return Virtual_Com_Port_NoData_Setup (RequestNo); -#else - return USB_UNSUPPORT; -#endif - } - else - return USB_UNSUPPORT; -} - -/* - * Interface to USB core - */ - -const DEVICE_PROP Device_Property = { - gnuk_device_init, - gnuk_device_reset, - gnuk_device_Status_In, - gnuk_device_Status_Out, - gnuk_setup_with_data, - gnuk_setup_with_nodata, - gnuk_device_Get_Interface_Setting, - gnuk_device_GetDeviceDescriptor, - gnuk_device_GetConfigDescriptor, - gnuk_device_GetStringDescriptor, - 0, - GNUK_MAX_PACKET_SIZE -}; - -const DEVICE Device_Table = { - EP_NUM, - 1 -}; - -const USER_STANDARD_REQUESTS User_Standard_Requests = { - NOP_Process, /* GetConfiguration */ - gnuk_device_SetConfiguration, - NOP_Process, /* GetInterface */ - gnuk_device_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 deleted file mode 100644 index b39196a..0000000 --- a/src/usb_prop.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __usb_prop_H -#define __usb_prop_H - -extern const ONE_DESCRIPTOR Device_Descriptor; -extern const ONE_DESCRIPTOR Config_Descriptor; -extern const ONE_DESCRIPTOR String_Descriptor[4]; -#endif /* __usb_prop_H */ diff --git a/src/vcomport.mk b/src/vcomport.mk deleted file mode 100644 index b545ae8..0000000 --- a/src/vcomport.mk +++ /dev/null @@ -1,5 +0,0 @@ -VCOMDIR = ../Virtual_COM_Port -VCOMSRC= $(VCOMDIR)/usb_istr.c $(VCOMDIR)/usb_pwr.c -ifneq ($(ENABLE_VCOMPORT),) -VCOMSRC += usb_endp.c -endif diff --git a/test/README b/test/README new file mode 100644 index 0000000..ddcde9c --- /dev/null +++ b/test/README @@ -0,0 +1,20 @@ +This is a functionality test suite for Gnuk. + +You need python-nose, python-freshen as well as python-usb. + +Besides, python-crypto is needed when you use generate_keys.py to +update contents of *.key. + + +Type: + + $ nosetests --with-freshen + +or + + $ nosetests -v --with-freshen + +to run the test suite. + +To skip tests for key generation, add an option "--tag ~keygen". To +stop running tests after the first error or failure, add "--stop" option. diff --git a/test/features/000_empty_check.feature b/test/features/000_empty_check.feature new file mode 100644 index 0000000..4f4d35e --- /dev/null +++ b/test/features/000_empty_check.feature @@ -0,0 +1,79 @@ +Feature: confirm empty token + In order to start tests + A token should be empty (no data, no keys) + + Scenario: data object Login + When requesting login data: 5e + Then you should get NULL + + Scenario: data object Name + When requesting name: 5b + Then you should get NULL + + Scenario: data object Language preference + When requesting anguage preference: 5f2d + Then you should get NULL + + Scenario: data object Sex + When requesting sex: 5f35 + Then you should get NULL + + Scenario: data object URL + When requesting URL: 5f50 + Then you should get NULL + + Scenario: data object ds counter + When requesting ds counter: 93 + Then you should get: \x00\x00\x00 + + Scenario: data object pw1 status bytes + When requesting pw1 status bytes: c4 + Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03 + + Scenario: data object finger print 0 + When requesting finger print: c5 + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object finger print 1 + When requesting finger print: c7 + Then you should get NULL + + Scenario: data object finger print 2 + When requesting finger print: c8 + Then you should get NULL + + Scenario: data object finger print 3 + When requesting finger print: c9 + Then you should get NULL + + Scenario: data object CA finger print 0 + When requesting finger print: c6 + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object CA finger print 1 + When requesting finger print: ca + Then you should get NULL + + Scenario: data object CA finger print 2 + When requesting finger print: cb + Then you should get NULL + + Scenario: data object CA finger print 3 + When requesting finger print: cc + Then you should get NULL + + Scenario: data object date/time of key pair 0 + When requesting date/time of key pair: cd + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object date/time of key pair 1 + When requesting date/time of key pair: ce + Then you should get NULL + + Scenario: data object date/time of key pair 2 + When requesting date/time of key pair: cf + Then you should get NULL + + Scenario: data object date/time of key pair 3 + When requesting date/time of key pair: d0 + Then you should get NULL diff --git a/test/features/001_empty_check_passphrase.feature b/test/features/001_empty_check_passphrase.feature new file mode 100644 index 0000000..f026b08 --- /dev/null +++ b/test/features/001_empty_check_passphrase.feature @@ -0,0 +1,15 @@ +Feature: confirm empty token + In order to start tests + A token should be empty (no pass phrase) + + Scenario: verify PW1 factory setting (1) + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW1 factory setting (2) + Given cmd_verify with 2 and "123456" + Then it should get success + + Scenario: verify PW3 factory setting + Given cmd_verify with 3 and "12345678" + Then it should get success diff --git a/test/features/002_get_data_static.feature b/test/features/002_get_data_static.feature new file mode 100644 index 0000000..63d31c7 --- /dev/null +++ b/test/features/002_get_data_static.feature @@ -0,0 +1,27 @@ +Feature: command GET DATA + In order to conform OpenPGP card 2.0 specification + A token should support all mandatory features of the specification + + Scenario: data object historical bytes + When requesting historical bytes: 5f52 + Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00 + + Scenario: data object extended capabilities + When requesting extended capabilities: c0 + Then data should match: \x30\x00\x00\x00[\x00\x08]\x00\x00\xff\x01\x00 + + Scenario: data object algorithm attributes 1 + When requesting algorithm attributes 1: c1 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object algorithm attributes 2 + When requesting algorithm attributes 2: c2 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object algorithm attributes 3 + When requesting algorighm attributes 3: c3 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object AID + When requesting AID: 4f + Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00 diff --git a/test/features/010_setup_passphrase.feature b/test/features/010_setup_passphrase.feature new file mode 100644 index 0000000..1ddcc23 --- /dev/null +++ b/test/features/010_setup_passphrase.feature @@ -0,0 +1,63 @@ +Feature: setup pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: setup PW1 (admin-less mode) + Given cmd_change_reference_data with 1 and "123456user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) + Given cmd_verify with 1 and "user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) + Given cmd_verify with 2 and "user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "user pass phrase" + Then it should get success + + Scenario: setup reset code (in admin-less mode) + Given cmd_put_data with d3 and "example reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-less mode) + Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) again + Given cmd_verify with 3 and "new user pass phrase" + Then it should get success + + Scenario: setup PW3 (admin-full mode) + Given cmd_change_reference_data with 3 and "new user pass phraseadmin pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-full mode) + Given cmd_verify with 3 and "admin pass phrase" + Then it should get success + + Scenario: setup reset code (in admin-full mode) + Given cmd_put_data with d3 and "another reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-full mode) + Given cmd_reset_retry_counter with 0 and "another reset code 000another user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success diff --git a/test/features/020_personalization_write.feature b/test/features/020_personalization_write.feature new file mode 100644 index 0000000..2fdd387 --- /dev/null +++ b/test/features/020_personalization_write.feature @@ -0,0 +1,27 @@ +Feature: personalize token write + In order to use a token + A token should be personalized with name, sex, url, etc. + + Scenario: data object Login + Given cmd_put_data with 5e and "gpg_user" + Then it should get success + + Scenario: data object Name + Given cmd_put_data with 5b and "GnuPG User" + Then it should get success + + Scenario: data object Language preference + Given cmd_put_data with 5f2d and "ja" + Then it should get success + + Scenario: data object Sex + Given cmd_put_data with 5f35 and "1" + Then it should get success + + Scenario: data object URL + Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/" + Then it should get success + + Scenario: data object pw1 status bytes + Given cmd_put_data with c4 and "\x01" + Then it should get success diff --git a/test/features/021_personalization_read.feature b/test/features/021_personalization_read.feature new file mode 100644 index 0000000..5f0f972 --- /dev/null +++ b/test/features/021_personalization_read.feature @@ -0,0 +1,27 @@ +Feature: personalize token read + In order to use a token + A token should be personalized with name, sex, url, etc. + + Scenario: data object Login + When requesting login data: 5e + Then you should get: gpg_user + + Scenario: data object Name + When requesting name: 5b + Then you should get: GnuPG User + + Scenario: data object Language preference + When requesting anguage preference: 5f2d + Then you should get: ja + + Scenario: data object Sex + When requesting sex: 5f35 + Then you should get: 1 + + Scenario: data object URL + When requesting URL: 5f50 + Then you should get: http://www.fsij.org/gnuk/ + + Scenario: data object pw1 status bytes + When requesting pw1 status bytes: c4 + Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03 diff --git a/test/features/030_key_registration.feature b/test/features/030_key_registration.feature new file mode 100644 index 0000000..4381307 --- /dev/null +++ b/test/features/030_key_registration.feature @@ -0,0 +1,56 @@ +Feature: import keys to token + In order to use a token + A token should have keys + + Scenario: importing OPENPGP.1 key (sign) + Given a RSA key pair 0 + And importing it to the token as OPENPGP.1 + Then it should get success + + Scenario: importing OPENPGP.2 key (decrypt) + Given a RSA key pair 1 + And importing it to the token as OPENPGP.2 + Then it should get success + + Scenario: importing OPENPGP.3 key (authentication) + Given a RSA key pair 2 + And importing it to the token as OPENPGP.3 + Then it should get success + + Scenario: setup data object Finger print sig + Given a fingerprint of OPENPGP.1 key + And put the data to c7 + Then it should get success + + Scenario: setup data object Finger print dec + Given a fingerprint of OPENPGP.2 key + And put the data to c8 + Then it should get success + + Scenario: setup data object Finger print aut + Given a fingerprint of OPENPGP.3 key + And put the data to c9 + Then it should get success + + Scenario: setup data object keygeneration data/time sig + Given a timestamp of OPENPGP.1 key + And put the data to ce + Then it should get success + + Scenario: setup data object keygeneration data/time dec + Given a timestamp of OPENPGP.2 key + And put the data to cf + Then it should get success + + Scenario: setup data object keygeneration data/time aut + Given a timestamp of OPENPGP.3 key + And put the data to d0 + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success diff --git a/test/features/040_passphrase_change.feature b/test/features/040_passphrase_change.feature new file mode 100644 index 0000000..3aaf750 --- /dev/null +++ b/test/features/040_passphrase_change.feature @@ -0,0 +1,71 @@ +Feature: change pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: setup reset code again (in admin-full mode) + Given cmd_put_data with d3 and "example reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-full mode) + Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: change PW3 (admin-full mode) + Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-full mode) + Given cmd_verify with 3 and "another admin pass phrase" + Then it should get success + + Scenario: reset pass phrase by admin (in admin-full mode) + Given cmd_reset_retry_counter with 2 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success + + Scenario: change PW3 (admin-full mode) + Given cmd_change_reference_data with 3 and "another admin pass phraseadmin pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-full mode) + Given cmd_verify with 3 and "admin pass phrase" + Then it should get success diff --git a/test/features/100_compute_signature.feature b/test/features/100_compute_signature.feature new file mode 100644 index 0000000..67fcbcc --- /dev/null +++ b/test/features/100_compute_signature.feature @@ -0,0 +1,31 @@ +Feature: compute digital signature + In order to use a token + A token should compute digital signature properly + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "This is a test message." + And let a token compute digital signature + And compute digital signature on host with RSA key pair 0 + Then results should be same + + Scenario: compute digital signature by OPENPGP.1 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And let a token compute digital signature + And compute digital signature on host with RSA key pair 0 + Then results should be same + + Scenario: compute digital signature by OPENPGP.3 key (1) + Given a message "This is a test message." + And let a token authenticate + And compute digital signature on host with RSA key pair 2 + Then results should be same + + Scenario: compute digital signature by OPENPGP.3 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And let a token authenticate + And compute digital signature on host with RSA key pair 2 + Then results should be same + + Scenario: data object ds counter + When requesting ds counter: 93 + Then you should get: \x00\x00\x02 diff --git a/test/features/101_decryption.feature b/test/features/101_decryption.feature new file mode 100644 index 0000000..1985dee --- /dev/null +++ b/test/features/101_decryption.feature @@ -0,0 +1,16 @@ +Feature: decryption + In order to use a token + A token should decrypt encrypted data + + Scenario: decrypt by OPENPGP.2 key (1) + Given a plain text "This is a test message." + And encrypt it on host with RSA key pair 1 + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + + Scenario: decrypt by OPENPGP.2 key (2) + Given a plain text "RSA decryption is as easy as pie." + And encrypt it on host with RSA key pair 1 + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + diff --git a/test/features/200_key_removal.feature b/test/features/200_key_removal.feature new file mode 100644 index 0000000..2582c25 --- /dev/null +++ b/test/features/200_key_removal.feature @@ -0,0 +1,40 @@ +@keygen +Feature: key removal + In order to use a token + A token should have keys + + Scenario: remove OPENPGP.1 key (sign) + When removing a key OPENPGP.1 + Then it should get success + + Scenario: remove OPENPGP.2 key (decrypt) + When removing a key OPENPGP.2 + Then it should get success + + Scenario: remove OPENPGP.3 key (authentication) + When removing a key OPENPGP.3 + Then it should get success + + Scenario: remove data object Finger print sig + Given cmd_put_data with c7 and "" + Then it should get success + + Scenario: remove data object Finger print dec + Given cmd_put_data with c8 and "" + Then it should get success + + Scenario: remove data object Finger print aut + Given cmd_put_data with c9 and "" + Then it should get success + + Scenario: remove data object keygeneration data/time sig + Given cmd_put_data with ce and "" + Then it should get success + + Scenario: remove data object keygeneration data/time dec + Given cmd_put_data with cf and "" + Then it should get success + + Scenario: remove data object keygeneration data/time aut + Given cmd_put_data with d0 and "" + Then it should get success diff --git a/test/features/201_setup_passphrase.feature b/test/features/201_setup_passphrase.feature new file mode 100644 index 0000000..dd223cb --- /dev/null +++ b/test/features/201_setup_passphrase.feature @@ -0,0 +1,32 @@ +@keygen +Feature: setup pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: setup PW1 (admin-full mode) + Given cmd_change_reference_data with 1 and "123456user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) + Given cmd_verify with 1 and "user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) + Given cmd_verify with 2 and "user pass phrase" + Then it should get success + + Scenario: setup reset code (in admin-full mode) + Given cmd_put_data with d3 and "example reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-full mode) + Given cmd_reset_retry_counter with 0 and "example reset code 000another user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success diff --git a/test/features/202_keygen.feature b/test/features/202_keygen.feature new file mode 100644 index 0000000..dcecf32 --- /dev/null +++ b/test/features/202_keygen.feature @@ -0,0 +1,37 @@ +@keygen +Feature: key generation + In order to use a token + A token should have keys + + Scenario: generate OPENPGP.1 key (sign) + When generating a key of OPENPGP.1 + And put the first data to c7 + And put the second data to ce + Then it should get success + + Scenario: generate OPENPGP.2 key (decrypt) + When generating a key of OPENPGP.2 + And put the first data to c8 + And put the second data to cf + Then it should get success + + Scenario: generate OPENPGP.3 key (authentication) + When generating a key of OPENPGP.3 + And put the first data to c9 + And put the second data to d0 + Then it should get success + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "GnuPG assumes that PW1 keeps valid after keygen." + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: verify PW1 (1) after keygen + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) after keygen + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success diff --git a/test/features/203_passphrase_change.feature b/test/features/203_passphrase_change.feature new file mode 100644 index 0000000..e392f0b --- /dev/null +++ b/test/features/203_passphrase_change.feature @@ -0,0 +1,71 @@ +Feature: change pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: setup reset code again (in admin-full mode) + Given cmd_put_data with d3 and "example reset code 111" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-full mode) + Given cmd_reset_retry_counter with 0 and "example reset code 111new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: change PW3 (admin-full mode) + Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-full mode) + Given cmd_verify with 3 and "another admin pass phrase" + Then it should get success + + Scenario: reset pass phrase by admin (in admin-full mode) + Given cmd_reset_retry_counter with 2 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success + + Scenario: change PW3 (admin-full mode) + Given cmd_change_reference_data with 3 and "another admin pass phraseadmin pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-full mode) + Given cmd_verify with 3 and "admin pass phrase" + Then it should get success diff --git a/test/features/210_compute_signature.feature b/test/features/210_compute_signature.feature new file mode 100644 index 0000000..7d9398b --- /dev/null +++ b/test/features/210_compute_signature.feature @@ -0,0 +1,36 @@ +@keygen +Feature: compute digital signature + In order to use a token + A token should compute digital signature properly + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "This is a test message." + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.1 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.3 key (1) + Given a message "This is a test message." + And a public key from token for OPENPGP.3 + And let a token authenticate + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.3 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And a public key from token for OPENPGP.3 + And let a token authenticate + And verify signature + Then it should get success + + Scenario: data object ds counter + When requesting ds counter: 93 + Then data should match: \x00\x00(\x02|\x03) diff --git a/test/features/211_decryption.feature b/test/features/211_decryption.feature new file mode 100644 index 0000000..e1cc98c --- /dev/null +++ b/test/features/211_decryption.feature @@ -0,0 +1,19 @@ +@keygen +Feature: decryption + In order to use a token + A token should decrypt encrypted data + + Scenario: decrypt by OPENPGP.2 key (1) + Given a plain text "This is a test message." + And a public key from token for OPENPGP.2 + And encrypt it on host + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + + Scenario: decrypt by OPENPGP.2 key (2) + Given a plain text "RSA decryption is as easy as pie." + And a public key from token for OPENPGP.2 + And encrypt it on host + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + diff --git a/test/features/370_key_removal.feature b/test/features/370_key_removal.feature new file mode 100644 index 0000000..5f89bc1 --- /dev/null +++ b/test/features/370_key_removal.feature @@ -0,0 +1,39 @@ +Feature: key removal + In order to use a token + A token should have keys + + Scenario: remove OPENPGP.1 key (sign) + When removing a key OPENPGP.1 + Then it should get success + + Scenario: remove OPENPGP.2 key (decrypt) + When removing a key OPENPGP.2 + Then it should get success + + Scenario: remove OPENPGP.3 key (authentication) + When removing a key OPENPGP.3 + Then it should get success + + Scenario: remove data object Finger print sig + Given cmd_put_data with c7 and "" + Then it should get success + + Scenario: remove data object Finger print dec + Given cmd_put_data with c8 and "" + Then it should get success + + Scenario: remove data object Finger print aut + Given cmd_put_data with c9 and "" + Then it should get success + + Scenario: remove data object keygeneration data/time sig + Given cmd_put_data with ce and "" + Then it should get success + + Scenario: remove data object keygeneration data/time dec + Given cmd_put_data with cf and "" + Then it should get success + + Scenario: remove data object keygeneration data/time aut + Given cmd_put_data with d0 and "" + Then it should get success diff --git a/test/features/380_personalization_reset.feature b/test/features/380_personalization_reset.feature new file mode 100644 index 0000000..51a3430 --- /dev/null +++ b/test/features/380_personalization_reset.feature @@ -0,0 +1,27 @@ +Feature: removal of data objects + In order to use a token + A token should have personalized data + + Scenario: remove data object Login + Given cmd_put_data with 5e and "" + Then it should get success + + Scenario: remove data object Name + Given cmd_put_data with 5b and "" + Then it should get success + + Scenario: remove data object Language preference + Given cmd_put_data with 5f2d and "" + Then it should get success + + Scenario: remove data object Sex + Given cmd_put_data with 5f35 and "" + Then it should get success + + Scenario: remove data object URL + Given cmd_put_data with 5f50 and "" + Then it should get success + + Scenario: remove data object pw1 status bytes + Given cmd_put_data with c4 and "\x00" + Then it should get success diff --git a/test/features/390_reset_passphrase.feature b/test/features/390_reset_passphrase.feature new file mode 100644 index 0000000..853c515 --- /dev/null +++ b/test/features/390_reset_passphrase.feature @@ -0,0 +1,7 @@ +Feature: reset pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: setup PW3 (admin-full mode) + Given cmd_change_reference_data with 3 and "admin pass phrase" + Then it should get success diff --git a/test/features/400_empty_check.feature b/test/features/400_empty_check.feature new file mode 100644 index 0000000..4f4d35e --- /dev/null +++ b/test/features/400_empty_check.feature @@ -0,0 +1,79 @@ +Feature: confirm empty token + In order to start tests + A token should be empty (no data, no keys) + + Scenario: data object Login + When requesting login data: 5e + Then you should get NULL + + Scenario: data object Name + When requesting name: 5b + Then you should get NULL + + Scenario: data object Language preference + When requesting anguage preference: 5f2d + Then you should get NULL + + Scenario: data object Sex + When requesting sex: 5f35 + Then you should get NULL + + Scenario: data object URL + When requesting URL: 5f50 + Then you should get NULL + + Scenario: data object ds counter + When requesting ds counter: 93 + Then you should get: \x00\x00\x00 + + Scenario: data object pw1 status bytes + When requesting pw1 status bytes: c4 + Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03 + + Scenario: data object finger print 0 + When requesting finger print: c5 + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object finger print 1 + When requesting finger print: c7 + Then you should get NULL + + Scenario: data object finger print 2 + When requesting finger print: c8 + Then you should get NULL + + Scenario: data object finger print 3 + When requesting finger print: c9 + Then you should get NULL + + Scenario: data object CA finger print 0 + When requesting finger print: c6 + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object CA finger print 1 + When requesting finger print: ca + Then you should get NULL + + Scenario: data object CA finger print 2 + When requesting finger print: cb + Then you should get NULL + + Scenario: data object CA finger print 3 + When requesting finger print: cc + Then you should get NULL + + Scenario: data object date/time of key pair 0 + When requesting date/time of key pair: cd + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object date/time of key pair 1 + When requesting date/time of key pair: ce + Then you should get NULL + + Scenario: data object date/time of key pair 2 + When requesting date/time of key pair: cf + Then you should get NULL + + Scenario: data object date/time of key pair 3 + When requesting date/time of key pair: d0 + Then you should get NULL diff --git a/test/features/401_empty_check_passphrase.feature b/test/features/401_empty_check_passphrase.feature new file mode 100644 index 0000000..f026b08 --- /dev/null +++ b/test/features/401_empty_check_passphrase.feature @@ -0,0 +1,15 @@ +Feature: confirm empty token + In order to start tests + A token should be empty (no pass phrase) + + Scenario: verify PW1 factory setting (1) + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW1 factory setting (2) + Given cmd_verify with 2 and "123456" + Then it should get success + + Scenario: verify PW3 factory setting + Given cmd_verify with 3 and "12345678" + Then it should get success diff --git a/test/features/402_get_data_static.feature b/test/features/402_get_data_static.feature new file mode 100644 index 0000000..63d31c7 --- /dev/null +++ b/test/features/402_get_data_static.feature @@ -0,0 +1,27 @@ +Feature: command GET DATA + In order to conform OpenPGP card 2.0 specification + A token should support all mandatory features of the specification + + Scenario: data object historical bytes + When requesting historical bytes: 5f52 + Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00 + + Scenario: data object extended capabilities + When requesting extended capabilities: c0 + Then data should match: \x30\x00\x00\x00[\x00\x08]\x00\x00\xff\x01\x00 + + Scenario: data object algorithm attributes 1 + When requesting algorithm attributes 1: c1 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object algorithm attributes 2 + When requesting algorithm attributes 2: c2 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object algorithm attributes 3 + When requesting algorighm attributes 3: c3 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object AID + When requesting AID: 4f + Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00 diff --git a/test/features/410_setup_passphrase.feature b/test/features/410_setup_passphrase.feature new file mode 100644 index 0000000..5ac2543 --- /dev/null +++ b/test/features/410_setup_passphrase.feature @@ -0,0 +1,55 @@ +Feature: setup pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: setup PW1 (admin-less mode) + Given cmd_change_reference_data with 1 and "123456user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) + Given cmd_verify with 1 and "user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) + Given cmd_verify with 2 and "user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "user pass phrase" + Then it should get success + + Scenario: setup reset code (in admin-less mode) + Given cmd_put_data with d3 and "example reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-less mode) + Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) again + Given cmd_verify with 3 and "new user pass phrase" + Then it should get success + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) again + Given cmd_verify with 3 and "another user pass phrase" + Then it should get success diff --git a/test/features/420_personalization_write.feature b/test/features/420_personalization_write.feature new file mode 100644 index 0000000..2fdd387 --- /dev/null +++ b/test/features/420_personalization_write.feature @@ -0,0 +1,27 @@ +Feature: personalize token write + In order to use a token + A token should be personalized with name, sex, url, etc. + + Scenario: data object Login + Given cmd_put_data with 5e and "gpg_user" + Then it should get success + + Scenario: data object Name + Given cmd_put_data with 5b and "GnuPG User" + Then it should get success + + Scenario: data object Language preference + Given cmd_put_data with 5f2d and "ja" + Then it should get success + + Scenario: data object Sex + Given cmd_put_data with 5f35 and "1" + Then it should get success + + Scenario: data object URL + Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/" + Then it should get success + + Scenario: data object pw1 status bytes + Given cmd_put_data with c4 and "\x01" + Then it should get success diff --git a/test/features/421_personalization_read.feature b/test/features/421_personalization_read.feature new file mode 100644 index 0000000..5f0f972 --- /dev/null +++ b/test/features/421_personalization_read.feature @@ -0,0 +1,27 @@ +Feature: personalize token read + In order to use a token + A token should be personalized with name, sex, url, etc. + + Scenario: data object Login + When requesting login data: 5e + Then you should get: gpg_user + + Scenario: data object Name + When requesting name: 5b + Then you should get: GnuPG User + + Scenario: data object Language preference + When requesting anguage preference: 5f2d + Then you should get: ja + + Scenario: data object Sex + When requesting sex: 5f35 + Then you should get: 1 + + Scenario: data object URL + When requesting URL: 5f50 + Then you should get: http://www.fsij.org/gnuk/ + + Scenario: data object pw1 status bytes + When requesting pw1 status bytes: c4 + Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03 diff --git a/test/features/430_key_registration.feature b/test/features/430_key_registration.feature new file mode 100644 index 0000000..4381307 --- /dev/null +++ b/test/features/430_key_registration.feature @@ -0,0 +1,56 @@ +Feature: import keys to token + In order to use a token + A token should have keys + + Scenario: importing OPENPGP.1 key (sign) + Given a RSA key pair 0 + And importing it to the token as OPENPGP.1 + Then it should get success + + Scenario: importing OPENPGP.2 key (decrypt) + Given a RSA key pair 1 + And importing it to the token as OPENPGP.2 + Then it should get success + + Scenario: importing OPENPGP.3 key (authentication) + Given a RSA key pair 2 + And importing it to the token as OPENPGP.3 + Then it should get success + + Scenario: setup data object Finger print sig + Given a fingerprint of OPENPGP.1 key + And put the data to c7 + Then it should get success + + Scenario: setup data object Finger print dec + Given a fingerprint of OPENPGP.2 key + And put the data to c8 + Then it should get success + + Scenario: setup data object Finger print aut + Given a fingerprint of OPENPGP.3 key + And put the data to c9 + Then it should get success + + Scenario: setup data object keygeneration data/time sig + Given a timestamp of OPENPGP.1 key + And put the data to ce + Then it should get success + + Scenario: setup data object keygeneration data/time dec + Given a timestamp of OPENPGP.2 key + And put the data to cf + Then it should get success + + Scenario: setup data object keygeneration data/time aut + Given a timestamp of OPENPGP.3 key + And put the data to d0 + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success diff --git a/test/features/440_passphrase_change.feature b/test/features/440_passphrase_change.feature new file mode 100644 index 0000000..9f567e6 --- /dev/null +++ b/test/features/440_passphrase_change.feature @@ -0,0 +1,51 @@ +Feature: change pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: change PW1 (in admin-less mode) + Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: setup reset code again (in admin-less mode) + Given cmd_put_data with d3 and "example reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-less mode) + Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "another user pass phrase" + Then it should get success diff --git a/test/features/500_compute_signature.feature b/test/features/500_compute_signature.feature new file mode 100644 index 0000000..67fcbcc --- /dev/null +++ b/test/features/500_compute_signature.feature @@ -0,0 +1,31 @@ +Feature: compute digital signature + In order to use a token + A token should compute digital signature properly + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "This is a test message." + And let a token compute digital signature + And compute digital signature on host with RSA key pair 0 + Then results should be same + + Scenario: compute digital signature by OPENPGP.1 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And let a token compute digital signature + And compute digital signature on host with RSA key pair 0 + Then results should be same + + Scenario: compute digital signature by OPENPGP.3 key (1) + Given a message "This is a test message." + And let a token authenticate + And compute digital signature on host with RSA key pair 2 + Then results should be same + + Scenario: compute digital signature by OPENPGP.3 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And let a token authenticate + And compute digital signature on host with RSA key pair 2 + Then results should be same + + Scenario: data object ds counter + When requesting ds counter: 93 + Then you should get: \x00\x00\x02 diff --git a/test/features/501_decryption.feature b/test/features/501_decryption.feature new file mode 100644 index 0000000..1985dee --- /dev/null +++ b/test/features/501_decryption.feature @@ -0,0 +1,16 @@ +Feature: decryption + In order to use a token + A token should decrypt encrypted data + + Scenario: decrypt by OPENPGP.2 key (1) + Given a plain text "This is a test message." + And encrypt it on host with RSA key pair 1 + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + + Scenario: decrypt by OPENPGP.2 key (2) + Given a plain text "RSA decryption is as easy as pie." + And encrypt it on host with RSA key pair 1 + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + diff --git a/test/features/600_key_removal.feature b/test/features/600_key_removal.feature new file mode 100644 index 0000000..2bcf353 --- /dev/null +++ b/test/features/600_key_removal.feature @@ -0,0 +1,44 @@ +@keygen +Feature: key removal + In order to use a token + A token should have keys + + Scenario: remove OPENPGP.1 key (sign) + When removing a key OPENPGP.1 + Then it should get success + + Scenario: remove OPENPGP.2 key (decrypt) + When removing a key OPENPGP.2 + Then it should get success + + Scenario: remove OPENPGP.3 key (authentication) + When removing a key OPENPGP.3 + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "12345678" + Then it should get success + + Scenario: remove data object Finger print sig + Given cmd_put_data with c7 and "" + Then it should get success + + Scenario: remove data object Finger print dec + Given cmd_put_data with c8 and "" + Then it should get success + + Scenario: remove data object Finger print aut + Given cmd_put_data with c9 and "" + Then it should get success + + Scenario: remove data object keygeneration data/time sig + Given cmd_put_data with ce and "" + Then it should get success + + Scenario: remove data object keygeneration data/time dec + Given cmd_put_data with cf and "" + Then it should get success + + Scenario: remove data object keygeneration data/time aut + Given cmd_put_data with d0 and "" + Then it should get success diff --git a/test/features/601_setup_passphrase.feature b/test/features/601_setup_passphrase.feature new file mode 100644 index 0000000..476c2b0 --- /dev/null +++ b/test/features/601_setup_passphrase.feature @@ -0,0 +1,40 @@ +@keygen +Feature: setup pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: setup PW1 (admin-less mode) + Given cmd_change_reference_data with 1 and "123456user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) + Given cmd_verify with 1 and "user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) + Given cmd_verify with 2 and "user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "user pass phrase" + Then it should get success + + Scenario: setup reset code (in admin-less mode) + Given cmd_put_data with d3 and "example reset code 000" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-less mode) + Given cmd_reset_retry_counter with 0 and "example reset code 000another user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) again + Given cmd_verify with 3 and "another user pass phrase" + Then it should get success diff --git a/test/features/602_keygen.feature b/test/features/602_keygen.feature new file mode 100644 index 0000000..dcecf32 --- /dev/null +++ b/test/features/602_keygen.feature @@ -0,0 +1,37 @@ +@keygen +Feature: key generation + In order to use a token + A token should have keys + + Scenario: generate OPENPGP.1 key (sign) + When generating a key of OPENPGP.1 + And put the first data to c7 + And put the second data to ce + Then it should get success + + Scenario: generate OPENPGP.2 key (decrypt) + When generating a key of OPENPGP.2 + And put the first data to c8 + And put the second data to cf + Then it should get success + + Scenario: generate OPENPGP.3 key (authentication) + When generating a key of OPENPGP.3 + And put the first data to c9 + And put the second data to d0 + Then it should get success + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "GnuPG assumes that PW1 keeps valid after keygen." + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: verify PW1 (1) after keygen + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) after keygen + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success diff --git a/test/features/603_passphrase_change.feature b/test/features/603_passphrase_change.feature new file mode 100644 index 0000000..accb4b8 --- /dev/null +++ b/test/features/603_passphrase_change.feature @@ -0,0 +1,67 @@ +Feature: change pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "PASSPHRASE SHOULD BE LONG" + Then it should get success + + Scenario: setup reset code again (in admin-less mode) + Given cmd_put_data with d3 and "example reset code 111" + Then it should get success + + Scenario: reset pass phrase by reset code (in admin-less mode) + Given cmd_reset_retry_counter with 0 and "example reset code 111new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "new user pass phrase" + Then it should get success + + Scenario: reset pass phrase by admin (in admin-less mode) + Given cmd_reset_retry_counter with 2 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "new user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "new user pass phrase" + Then it should get success + + Scenario: change PW1 + Given cmd_change_reference_data with 1 and "new user pass phraseanother user pass phrase" + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "another user pass phrase" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "another user pass phrase" + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "another user pass phrase" + Then it should get success diff --git a/test/features/610_compute_signature.feature b/test/features/610_compute_signature.feature new file mode 100644 index 0000000..7d9398b --- /dev/null +++ b/test/features/610_compute_signature.feature @@ -0,0 +1,36 @@ +@keygen +Feature: compute digital signature + In order to use a token + A token should compute digital signature properly + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "This is a test message." + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.1 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.3 key (1) + Given a message "This is a test message." + And a public key from token for OPENPGP.3 + And let a token authenticate + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.3 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And a public key from token for OPENPGP.3 + And let a token authenticate + And verify signature + Then it should get success + + Scenario: data object ds counter + When requesting ds counter: 93 + Then data should match: \x00\x00(\x02|\x03) diff --git a/test/features/611_decryption.feature b/test/features/611_decryption.feature new file mode 100644 index 0000000..e1cc98c --- /dev/null +++ b/test/features/611_decryption.feature @@ -0,0 +1,19 @@ +@keygen +Feature: decryption + In order to use a token + A token should decrypt encrypted data + + Scenario: decrypt by OPENPGP.2 key (1) + Given a plain text "This is a test message." + And a public key from token for OPENPGP.2 + And encrypt it on host + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + + Scenario: decrypt by OPENPGP.2 key (2) + Given a plain text "RSA decryption is as easy as pie." + And a public key from token for OPENPGP.2 + And encrypt it on host + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + diff --git a/test/features/770_key_removal.feature b/test/features/770_key_removal.feature new file mode 100644 index 0000000..a8c50b1 --- /dev/null +++ b/test/features/770_key_removal.feature @@ -0,0 +1,43 @@ +Feature: key removal + In order to use a token + A token should have keys + + Scenario: remove OPENPGP.1 key (sign) + When removing a key OPENPGP.1 + Then it should get success + + Scenario: remove OPENPGP.2 key (decrypt) + When removing a key OPENPGP.2 + Then it should get success + + Scenario: remove OPENPGP.3 key (authentication) + When removing a key OPENPGP.3 + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "12345678" + Then it should get success + + Scenario: remove data object Finger print sig + Given cmd_put_data with c7 and "" + Then it should get success + + Scenario: remove data object Finger print dec + Given cmd_put_data with c8 and "" + Then it should get success + + Scenario: remove data object Finger print aut + Given cmd_put_data with c9 and "" + Then it should get success + + Scenario: remove data object keygeneration data/time sig + Given cmd_put_data with ce and "" + Then it should get success + + Scenario: remove data object keygeneration data/time dec + Given cmd_put_data with cf and "" + Then it should get success + + Scenario: remove data object keygeneration data/time aut + Given cmd_put_data with d0 and "" + Then it should get success diff --git a/test/features/780_personalization_reset.feature b/test/features/780_personalization_reset.feature new file mode 100644 index 0000000..51a3430 --- /dev/null +++ b/test/features/780_personalization_reset.feature @@ -0,0 +1,27 @@ +Feature: removal of data objects + In order to use a token + A token should have personalized data + + Scenario: remove data object Login + Given cmd_put_data with 5e and "" + Then it should get success + + Scenario: remove data object Name + Given cmd_put_data with 5b and "" + Then it should get success + + Scenario: remove data object Language preference + Given cmd_put_data with 5f2d and "" + Then it should get success + + Scenario: remove data object Sex + Given cmd_put_data with 5f35 and "" + Then it should get success + + Scenario: remove data object URL + Given cmd_put_data with 5f50 and "" + Then it should get success + + Scenario: remove data object pw1 status bytes + Given cmd_put_data with c4 and "\x00" + Then it should get success diff --git a/test/features/790_reset_passphrase.feature b/test/features/790_reset_passphrase.feature new file mode 100644 index 0000000..78edf9a --- /dev/null +++ b/test/features/790_reset_passphrase.feature @@ -0,0 +1,7 @@ +Feature: confirm factory setting pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "12345678" + Then it should get success diff --git a/test/features/800_empty_check.feature b/test/features/800_empty_check.feature new file mode 100644 index 0000000..4f4d35e --- /dev/null +++ b/test/features/800_empty_check.feature @@ -0,0 +1,79 @@ +Feature: confirm empty token + In order to start tests + A token should be empty (no data, no keys) + + Scenario: data object Login + When requesting login data: 5e + Then you should get NULL + + Scenario: data object Name + When requesting name: 5b + Then you should get NULL + + Scenario: data object Language preference + When requesting anguage preference: 5f2d + Then you should get NULL + + Scenario: data object Sex + When requesting sex: 5f35 + Then you should get NULL + + Scenario: data object URL + When requesting URL: 5f50 + Then you should get NULL + + Scenario: data object ds counter + When requesting ds counter: 93 + Then you should get: \x00\x00\x00 + + Scenario: data object pw1 status bytes + When requesting pw1 status bytes: c4 + Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03 + + Scenario: data object finger print 0 + When requesting finger print: c5 + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object finger print 1 + When requesting finger print: c7 + Then you should get NULL + + Scenario: data object finger print 2 + When requesting finger print: c8 + Then you should get NULL + + Scenario: data object finger print 3 + When requesting finger print: c9 + Then you should get NULL + + Scenario: data object CA finger print 0 + When requesting finger print: c6 + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object CA finger print 1 + When requesting finger print: ca + Then you should get NULL + + Scenario: data object CA finger print 2 + When requesting finger print: cb + Then you should get NULL + + Scenario: data object CA finger print 3 + When requesting finger print: cc + Then you should get NULL + + Scenario: data object date/time of key pair 0 + When requesting date/time of key pair: cd + Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + + Scenario: data object date/time of key pair 1 + When requesting date/time of key pair: ce + Then you should get NULL + + Scenario: data object date/time of key pair 2 + When requesting date/time of key pair: cf + Then you should get NULL + + Scenario: data object date/time of key pair 3 + When requesting date/time of key pair: d0 + Then you should get NULL diff --git a/test/features/801_empty_check_passphrase.feature b/test/features/801_empty_check_passphrase.feature new file mode 100644 index 0000000..f026b08 --- /dev/null +++ b/test/features/801_empty_check_passphrase.feature @@ -0,0 +1,15 @@ +Feature: confirm empty token + In order to start tests + A token should be empty (no pass phrase) + + Scenario: verify PW1 factory setting (1) + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW1 factory setting (2) + Given cmd_verify with 2 and "123456" + Then it should get success + + Scenario: verify PW3 factory setting + Given cmd_verify with 3 and "12345678" + Then it should get success diff --git a/test/features/802_get_data_static.feature b/test/features/802_get_data_static.feature new file mode 100644 index 0000000..63d31c7 --- /dev/null +++ b/test/features/802_get_data_static.feature @@ -0,0 +1,27 @@ +Feature: command GET DATA + In order to conform OpenPGP card 2.0 specification + A token should support all mandatory features of the specification + + Scenario: data object historical bytes + When requesting historical bytes: 5f52 + Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00 + + Scenario: data object extended capabilities + When requesting extended capabilities: c0 + Then data should match: \x30\x00\x00\x00[\x00\x08]\x00\x00\xff\x01\x00 + + Scenario: data object algorithm attributes 1 + When requesting algorithm attributes 1: c1 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object algorithm attributes 2 + When requesting algorithm attributes 2: c2 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object algorithm attributes 3 + When requesting algorighm attributes 3: c3 + Then you should get: \x01\x08\x00\x00\x20\x00 + + Scenario: data object AID + When requesting AID: 4f + Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00 diff --git a/test/features/810_setup_passphrase.feature b/test/features/810_setup_passphrase.feature new file mode 100644 index 0000000..d3b086d --- /dev/null +++ b/test/features/810_setup_passphrase.feature @@ -0,0 +1,15 @@ +Feature: check pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: verify PW1 (1) + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW1 (2) + Given cmd_verify with 2 and "123456" + Then it should get success + + Scenario: verify PW3 + Given cmd_verify with 3 and "12345678" + Then it should get success diff --git a/test/features/820_personalization_write.feature b/test/features/820_personalization_write.feature new file mode 100644 index 0000000..2fdd387 --- /dev/null +++ b/test/features/820_personalization_write.feature @@ -0,0 +1,27 @@ +Feature: personalize token write + In order to use a token + A token should be personalized with name, sex, url, etc. + + Scenario: data object Login + Given cmd_put_data with 5e and "gpg_user" + Then it should get success + + Scenario: data object Name + Given cmd_put_data with 5b and "GnuPG User" + Then it should get success + + Scenario: data object Language preference + Given cmd_put_data with 5f2d and "ja" + Then it should get success + + Scenario: data object Sex + Given cmd_put_data with 5f35 and "1" + Then it should get success + + Scenario: data object URL + Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/" + Then it should get success + + Scenario: data object pw1 status bytes + Given cmd_put_data with c4 and "\x01" + Then it should get success diff --git a/test/features/821_personalization_read.feature b/test/features/821_personalization_read.feature new file mode 100644 index 0000000..5f0f972 --- /dev/null +++ b/test/features/821_personalization_read.feature @@ -0,0 +1,27 @@ +Feature: personalize token read + In order to use a token + A token should be personalized with name, sex, url, etc. + + Scenario: data object Login + When requesting login data: 5e + Then you should get: gpg_user + + Scenario: data object Name + When requesting name: 5b + Then you should get: GnuPG User + + Scenario: data object Language preference + When requesting anguage preference: 5f2d + Then you should get: ja + + Scenario: data object Sex + When requesting sex: 5f35 + Then you should get: 1 + + Scenario: data object URL + When requesting URL: 5f50 + Then you should get: http://www.fsij.org/gnuk/ + + Scenario: data object pw1 status bytes + When requesting pw1 status bytes: c4 + Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03 diff --git a/test/features/830_key_registration.feature b/test/features/830_key_registration.feature new file mode 100644 index 0000000..24246af --- /dev/null +++ b/test/features/830_key_registration.feature @@ -0,0 +1,56 @@ +Feature: import keys to token + In order to use a token + A token should have keys + + Scenario: importing OPENPGP.1 key (sign) + Given a RSA key pair 0 + And importing it to the token as OPENPGP.1 + Then it should get success + + Scenario: importing OPENPGP.2 key (decrypt) + Given a RSA key pair 1 + And importing it to the token as OPENPGP.2 + Then it should get success + + Scenario: importing OPENPGP.3 key (authentication) + Given a RSA key pair 2 + And importing it to the token as OPENPGP.3 + Then it should get success + + Scenario: setup data object Finger print sig + Given a fingerprint of OPENPGP.1 key + And put the data to c7 + Then it should get success + + Scenario: setup data object Finger print dec + Given a fingerprint of OPENPGP.2 key + And put the data to c8 + Then it should get success + + Scenario: setup data object Finger print aut + Given a fingerprint of OPENPGP.3 key + And put the data to c9 + Then it should get success + + Scenario: setup data object keygeneration data/time sig + Given a timestamp of OPENPGP.1 key + And put the data to ce + Then it should get success + + Scenario: setup data object keygeneration data/time dec + Given a timestamp of OPENPGP.2 key + And put the data to cf + Then it should get success + + Scenario: setup data object keygeneration data/time aut + Given a timestamp of OPENPGP.3 key + And put the data to d0 + Then it should get success + + Scenario: verify PW1 (1) again + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW1 (2) again + Given cmd_verify with 2 and "123456" + Then it should get success diff --git a/test/features/850_compute_signature.feature b/test/features/850_compute_signature.feature new file mode 100644 index 0000000..67fcbcc --- /dev/null +++ b/test/features/850_compute_signature.feature @@ -0,0 +1,31 @@ +Feature: compute digital signature + In order to use a token + A token should compute digital signature properly + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "This is a test message." + And let a token compute digital signature + And compute digital signature on host with RSA key pair 0 + Then results should be same + + Scenario: compute digital signature by OPENPGP.1 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And let a token compute digital signature + And compute digital signature on host with RSA key pair 0 + Then results should be same + + Scenario: compute digital signature by OPENPGP.3 key (1) + Given a message "This is a test message." + And let a token authenticate + And compute digital signature on host with RSA key pair 2 + Then results should be same + + Scenario: compute digital signature by OPENPGP.3 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And let a token authenticate + And compute digital signature on host with RSA key pair 2 + Then results should be same + + Scenario: data object ds counter + When requesting ds counter: 93 + Then you should get: \x00\x00\x02 diff --git a/test/features/851_decryption.feature b/test/features/851_decryption.feature new file mode 100644 index 0000000..1985dee --- /dev/null +++ b/test/features/851_decryption.feature @@ -0,0 +1,16 @@ +Feature: decryption + In order to use a token + A token should decrypt encrypted data + + Scenario: decrypt by OPENPGP.2 key (1) + Given a plain text "This is a test message." + And encrypt it on host with RSA key pair 1 + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + + Scenario: decrypt by OPENPGP.2 key (2) + Given a plain text "RSA decryption is as easy as pie." + And encrypt it on host with RSA key pair 1 + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + diff --git a/test/features/860_key_removal.feature b/test/features/860_key_removal.feature new file mode 100644 index 0000000..ad4db98 --- /dev/null +++ b/test/features/860_key_removal.feature @@ -0,0 +1,48 @@ +@keygen +Feature: key removal + In order to use a token + A token should have keys + + Scenario: remove OPENPGP.1 key (sign) + When removing a key OPENPGP.1 + Then it should get success + + Scenario: remove OPENPGP.2 key (decrypt) + When removing a key OPENPGP.2 + Then it should get success + + Scenario: remove OPENPGP.3 key (authentication) + When removing a key OPENPGP.3 + Then it should get success + + Scenario: remove data object Finger print sig + Given cmd_put_data with c7 and "" + Then it should get success + + Scenario: remove data object Finger print dec + Given cmd_put_data with c8 and "" + Then it should get success + + Scenario: remove data object Finger print aut + Given cmd_put_data with c9 and "" + Then it should get success + + Scenario: remove data object keygeneration data/time sig + Given cmd_put_data with ce and "" + Then it should get success + + Scenario: remove data object keygeneration data/time dec + Given cmd_put_data with cf and "" + Then it should get success + + Scenario: remove data object keygeneration data/time aut + Given cmd_put_data with d0 and "" + Then it should get success + + Scenario: verify PW1 + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW2 + Given cmd_verify with 2 and "123456" + Then it should get success diff --git a/test/features/862_keygen.feature b/test/features/862_keygen.feature new file mode 100644 index 0000000..9cbde5b --- /dev/null +++ b/test/features/862_keygen.feature @@ -0,0 +1,37 @@ +@keygen +Feature: key generation + In order to use a token + A token should have keys + + Scenario: generate OPENPGP.1 key (sign) + When generating a key of OPENPGP.1 + And put the first data to c7 + And put the second data to ce + Then it should get success + + Scenario: generate OPENPGP.2 key (decrypt) + When generating a key of OPENPGP.2 + And put the first data to c8 + And put the second data to cf + Then it should get success + + Scenario: generate OPENPGP.3 key (authentication) + When generating a key of OPENPGP.3 + And put the first data to c9 + And put the second data to d0 + Then it should get success + + Scenario: compute digital signature by OPENPGP.1 key + Given a message "GnuPG assumes that PW1 keeps valid after keygen." + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: verify PW1 (1) after keygen + Given cmd_verify with 1 and "123456" + Then it should get success + + Scenario: verify PW1 (2) after keygen + Given cmd_verify with 2 and "123456" + Then it should get success diff --git a/test/features/870_compute_signature.feature b/test/features/870_compute_signature.feature new file mode 100644 index 0000000..7d9398b --- /dev/null +++ b/test/features/870_compute_signature.feature @@ -0,0 +1,36 @@ +@keygen +Feature: compute digital signature + In order to use a token + A token should compute digital signature properly + + Scenario: compute digital signature by OPENPGP.1 key (1) + Given a message "This is a test message." + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.1 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And a public key from token for OPENPGP.1 + And let a token compute digital signature + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.3 key (1) + Given a message "This is a test message." + And a public key from token for OPENPGP.3 + And let a token authenticate + And verify signature + Then it should get success + + Scenario: compute digital signature by OPENPGP.3 key (2) + Given a message "This is another test message.\nMultiple lines.\n" + And a public key from token for OPENPGP.3 + And let a token authenticate + And verify signature + Then it should get success + + Scenario: data object ds counter + When requesting ds counter: 93 + Then data should match: \x00\x00(\x02|\x03) diff --git a/test/features/871_decryption.feature b/test/features/871_decryption.feature new file mode 100644 index 0000000..e1cc98c --- /dev/null +++ b/test/features/871_decryption.feature @@ -0,0 +1,19 @@ +@keygen +Feature: decryption + In order to use a token + A token should decrypt encrypted data + + Scenario: decrypt by OPENPGP.2 key (1) + Given a plain text "This is a test message." + And a public key from token for OPENPGP.2 + And encrypt it on host + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + + Scenario: decrypt by OPENPGP.2 key (2) + Given a plain text "RSA decryption is as easy as pie." + And a public key from token for OPENPGP.2 + And encrypt it on host + And let a token decrypt encrypted data + Then decrypted data should be same as a plain text + diff --git a/test/features/970_key_removal.feature b/test/features/970_key_removal.feature new file mode 100644 index 0000000..a8c50b1 --- /dev/null +++ b/test/features/970_key_removal.feature @@ -0,0 +1,43 @@ +Feature: key removal + In order to use a token + A token should have keys + + Scenario: remove OPENPGP.1 key (sign) + When removing a key OPENPGP.1 + Then it should get success + + Scenario: remove OPENPGP.2 key (decrypt) + When removing a key OPENPGP.2 + Then it should get success + + Scenario: remove OPENPGP.3 key (authentication) + When removing a key OPENPGP.3 + Then it should get success + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "12345678" + Then it should get success + + Scenario: remove data object Finger print sig + Given cmd_put_data with c7 and "" + Then it should get success + + Scenario: remove data object Finger print dec + Given cmd_put_data with c8 and "" + Then it should get success + + Scenario: remove data object Finger print aut + Given cmd_put_data with c9 and "" + Then it should get success + + Scenario: remove data object keygeneration data/time sig + Given cmd_put_data with ce and "" + Then it should get success + + Scenario: remove data object keygeneration data/time dec + Given cmd_put_data with cf and "" + Then it should get success + + Scenario: remove data object keygeneration data/time aut + Given cmd_put_data with d0 and "" + Then it should get success diff --git a/test/features/980_personalization_reset.feature b/test/features/980_personalization_reset.feature new file mode 100644 index 0000000..51a3430 --- /dev/null +++ b/test/features/980_personalization_reset.feature @@ -0,0 +1,27 @@ +Feature: removal of data objects + In order to use a token + A token should have personalized data + + Scenario: remove data object Login + Given cmd_put_data with 5e and "" + Then it should get success + + Scenario: remove data object Name + Given cmd_put_data with 5b and "" + Then it should get success + + Scenario: remove data object Language preference + Given cmd_put_data with 5f2d and "" + Then it should get success + + Scenario: remove data object Sex + Given cmd_put_data with 5f35 and "" + Then it should get success + + Scenario: remove data object URL + Given cmd_put_data with 5f50 and "" + Then it should get success + + Scenario: remove data object pw1 status bytes + Given cmd_put_data with c4 and "\x00" + Then it should get success diff --git a/test/features/990_reset_passphrase.feature b/test/features/990_reset_passphrase.feature new file mode 100644 index 0000000..78edf9a --- /dev/null +++ b/test/features/990_reset_passphrase.feature @@ -0,0 +1,7 @@ +Feature: confirm factory setting pass phrase + In order to conform OpenPGP card 2.0 specification + A token should support pass phrase: PW1, PW3 and reset code + + Scenario: verify PW3 (admin-less mode) + Given cmd_verify with 3 and "12345678" + Then it should get success diff --git a/test/features/991_version_string.feature b/test/features/991_version_string.feature new file mode 100644 index 0000000..9a10d4c --- /dev/null +++ b/test/features/991_version_string.feature @@ -0,0 +1,8 @@ +@usb +Feature: examine USB version string + In order to work as Gnuk Token + A token should support version string + + Scenario: USB version string + Given USB version string of the token + Then data should match: ([a-zA-Z0-9]*)-([.0-9]+)-[0-9A-F]+ diff --git a/test/features/steps.py b/test/features/steps.py new file mode 100644 index 0000000..dc915e2 --- /dev/null +++ b/test/features/steps.py @@ -0,0 +1,172 @@ +from freshen import * +from freshen.checks import * +from nose.tools import assert_regexp_matches +from binascii import hexlify + +import ast + +import gnuk_token as gnuk +import rsa_keys + +@Before +def ini(sc): + if not ftc.token: + ftc.token = gnuk.get_gnuk_device() + ftc.token.cmd_select_openpgp() + +@Given("cmd_verify with (.*) and \"(.*)\"") +def cmd_verify(who_str,pass_str): + who = int(who_str) + scc.result = ftc.token.cmd_verify(who, pass_str) + +@Given("cmd_change_reference_data with (.*) and \"(.*)\"") +def cmd_change_reference_data(who_str,pass_str): + who = int(who_str) + scc.result = ftc.token.cmd_change_reference_data(who, pass_str) + +@Given("cmd_put_data with (.*) and (\".*\")") +def cmd_put_data(tag_str,content_str_repr): + content_str = ast.literal_eval(content_str_repr) + tag = int(tag_str, 16) + tagh = tag >> 8 + tagl = tag & 0xff + scc.result = ftc.token.cmd_put_data(tagh, tagl, content_str) + +@Given("cmd_reset_retry_counter with (.*) and \"(.*)\"") +def cmd_reset_retry_counter(how_str, data): + how = int(how_str) + scc.result = ftc.token.cmd_reset_retry_counter(how, data) + +@Given("a RSA key pair (.*)") +def set_rsa_key(keyno_str): + scc.keyno = int(keyno_str) + +@Given("importing it to the token as OPENPGP.(.*)") +def import_key(openpgp_keyno_str): + openpgp_keyno = int(openpgp_keyno_str) + t = rsa_keys.build_privkey_template(openpgp_keyno, scc.keyno) + scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t) + +@Given("a fingerprint of OPENPGP.(.*) key") +def get_key_fpr(openpgp_keyno_str): + openpgp_keyno = int(openpgp_keyno_str) + scc.result = rsa_keys.fpr[openpgp_keyno - 1] + +@Given("a timestamp of OPENPGP.(.*) key") +def get_key_timestamp(openpgp_keyno_str): + openpgp_keyno = int(openpgp_keyno_str) + scc.result = rsa_keys.timestamp[openpgp_keyno - 1] + +@Given("put the data to (.*)") +def cmd_put_data_with_result(tag_str): + tag = int(tag_str, 16) + tagh = tag >> 8 + tagl = tag & 0xff + scc.result = ftc.token.cmd_put_data(tagh, tagl, scc.result) + +@Given("a message (\".*\")") +def set_msg(content_str_repr): + msg = ast.literal_eval(content_str_repr) + scc.digestinfo = rsa_keys.compute_digestinfo(msg) + +@Given("a public key from token for OPENPGP.(.*)") +def get_public_key(openpgp_keyno_str): + openpgp_keyno = int(openpgp_keyno_str) + scc.pubkey_info = ftc.token.cmd_get_public_key(openpgp_keyno) + +@Given("verify signature") +def verify_signature(): + scc.result = rsa_keys.verify_signature(scc.pubkey_info, scc.digestinfo, scc.sig) + +@Given("let a token compute digital signature") +def compute_signature(): + scc.sig = int(hexlify(ftc.token.cmd_pso(0x9e, 0x9a, scc.digestinfo)),16) + +@Given("let a token authenticate") +def internal_authenticate(): + scc.sig = int(hexlify(ftc.token.cmd_internal_authenticate(scc.digestinfo)),16) + +@Given("compute digital signature on host with RSA key pair (.*)") +def compute_signature_on_host(keyno_str): + keyno = int(keyno_str) + scc.result = rsa_keys.compute_signature(keyno, scc.digestinfo) + +@Given("a plain text (\".*\")") +def set_plaintext(content_str_repr): + scc.plaintext = ast.literal_eval(content_str_repr) + +@Given("encrypt it on host with RSA key pair (.*)$") +def encrypt_on_host(keyno_str): + keyno = int(keyno_str) + scc.ciphertext = rsa_keys.encrypt(keyno, scc.plaintext) + +@Given("encrypt it on host$") +def encrypt_on_host_public_key(): + scc.ciphertext = rsa_keys.encrypt_with_pubkey(scc.pubkey_info, scc.plaintext) + +@Given("let a token decrypt encrypted data") +def decrypt(): + scc.result = ftc.token.cmd_pso_longdata(0x80, 0x86, scc.ciphertext) + +@Given("USB version string of the token") +def usb_version_string(): + scc.result = ftc.token.get_string(3) + +@When("requesting (.+): ([0-9a-fA-F]+)") +def get_data(name, tag_str): + tag = int(tag_str, 16) + tagh = tag >> 8 + tagl = tag & 0xff + scc.result = ftc.token.cmd_get_data(tagh, tagl) + +@When("removing a key OPENPGP.(.*)") +def remove_key(openpgp_keyno_str): + openpgp_keyno = int(openpgp_keyno_str) + t = rsa_keys.build_privkey_template_for_remove(openpgp_keyno) + scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t) + +@When("generating a key of OPENPGP.(.*)") +def generate_key(openpgp_keyno_str): + openpgp_keyno = int(openpgp_keyno_str) + pubkey_info = ftc.token.cmd_genkey(openpgp_keyno) + scc.data = rsa_keys.calc_fpr(pubkey_info[0], pubkey_info[1]) + +@When("put the first data to (.*)") +def cmd_put_data_first_with_result(tag_str): + tag = int(tag_str, 16) + tagh = tag >> 8 + tagl = tag & 0xff + scc.result = ftc.token.cmd_put_data(tagh, tagl, scc.data[0]) + +@When("put the second data to (.*)") +def cmd_put_data_second_with_result(tag_str): + tag = int(tag_str, 16) + tagh = tag >> 8 + tagl = tag & 0xff + result = ftc.token.cmd_put_data(tagh, tagl, scc.data[1]) + scc.result = (scc.result and result) + +@Then("you should get: (.*)") +def check_result(v): + value = ast.literal_eval("'" + v + "'") + assert_equal(scc.result, value) + +@Then("it should get success") +def check_success(): + assert_equal(scc.result, True) + +@Then("you should get NULL") +def check_null(): + assert_equal(scc.result, "") + +@Then("data should match: (.*)") +def check_regexp(re): + assert_regexp_matches(scc.result, re) + +@Then("results should be same") +def check_signature(): + assert_equal(scc.sig, scc.result) + +@Then("decrypted data should be same as a plain text") +def check_decrypt(): + assert_equal(scc.plaintext, scc.result) diff --git a/test/generate_keys.py b/test/generate_keys.py new file mode 100644 index 0000000..8face41 --- /dev/null +++ b/test/generate_keys.py @@ -0,0 +1,25 @@ +from Crypto import Random +from Crypto.PublicKey import RSA +from binascii import hexlify + +def print_key_in_hex(k): + prv = k.exportKey(format='DER', pkcs=8) + n = prv[38:38+256] + e = prv[38+256+2:38+256+2+3] + p = prv[38+256+2+3+4+257+4:38+256+2+3+4+257+4+128] + q = prv[38+256+2+3+4+257+4+128+4:38+256+2+3+4+257+4+128+4+128] + n_str = hexlify(n) + e_str = hexlify(e) + p_str = hexlify(p) + q_str = hexlify(q) + if int(p_str, 16)*int(q_str, 16) != int(n_str, 16): + raise ValueError("wrong key", k) + print n_str + print e_str + print p_str + print q_str + +rng = Random.new().read +key = RSA.generate(2048, rng) + +print_key_in_hex(key) diff --git a/test/gnuk_token.py b/test/gnuk_token.py new file mode 120000 index 0000000..c89e721 --- /dev/null +++ b/test/gnuk_token.py @@ -0,0 +1 @@ +../tool/gnuk_token.py \ No newline at end of file diff --git a/test/rsa-aut.key b/test/rsa-aut.key new file mode 100644 index 0000000..cdf2d5e --- /dev/null +++ b/test/rsa-aut.key @@ -0,0 +1,4 @@ +9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9 +010001 +b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907 +dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf diff --git a/test/rsa-dec.key b/test/rsa-dec.key new file mode 100644 index 0000000..8c2aa47 --- /dev/null +++ b/test/rsa-dec.key @@ -0,0 +1,4 @@ +d392714c29738aac6372f2c8654a08c25a1299fed7004bd512cd2452b503ebad6301130816ac525ba528dc155be6347a5c70407fb4fbdaed751dfc0a7cd5e3910272ff236c4ed1ce5de6620b191a172e5b247347b8cab73a43d79221708755c959a2f83f486439da30917384554331532aabc8326db48866f8c91198834a86ab94679f6175db737bdf399e3f0b737dcb1f4208279d3e1cc694e78686785e4f363a377dec912b7c2f757b1422d866fb9fa85c96b83adfd6a223989a9a02988bdee81ad17eff6385e7b38cec8611fdf367ba4ac8e90d5f48ac7715c5f47aea06a4a37cdaa3029ce59d29bc66853bf6758ef4a7da5a5953f5e557a5a22f67c368c3 +010001 +dae085952c5beee38f25f09bc37a4ca2434c31f78055469d0d5f0bf3337e3a70ba6c91734f195b742e211a5fe283befdf66820008e6ef2c8ca54a91922838fce07d9e33a331ce20dac36803e777d5ee2195ed28d6a4045e28623a6a60b0661e45f7c4f84ae2b1dfad0cf1ec30605158323382a819e730c09a33fad704dd67501 +f774be43ea198aa2f089274e4fffd7d0092ee7b35a1d2f854cdb166f698caab72fdeb099e690e78438b2e043e452d4d2f19d7f44ba6b286642f0ce5204966ff98ecd9e3b448877324631365dc860797429b9414a21a7e166d504cace156588b9a145657eeb1afb43b8ff65d8d6d93cea2ba4ef8aab047885c4de64ffef0b49c3 diff --git a/test/rsa-sig.key b/test/rsa-sig.key new file mode 100644 index 0000000..c83179a --- /dev/null +++ b/test/rsa-sig.key @@ -0,0 +1,4 @@ +c6c877dfd3b441f8fb1b8dc504093a51c2efe4883fe0a6379205acc6e673709905e4d767ddf46143c535cc6d7f10b616f520d8346320ef69ff4a2c4f4a148edc65f7ad24ed7d4fe23bb862a0ae71f4f7904abac0397abf3213df91326b1a25554b3b18cf54584d8bf220169fc92b2aa511e8313983e72b4c9110b3a1aea087aebef95873865608e8faea9ef10e7f7f3a66ca8def2d499c3149c127491e0e4339fd6abe10bfc6c13e43d522004f1485767328eabe35d6ffa8df4c15f0fbcd4eb1c07cc6d85e275139ac69e2962273ae987236926dd6c1144fce3e7ae567fa58ea60620dfafc52f95299fea601739fce27ee71eea978d0074f21e7086f60ba8331 +010001 +cc365b5702714bf203e8c49b0b8afa8dad586e929cf5edca38ad07fa45efd5c2d89022d29f40283a57e50ca24c5f28c8e911a74faaf796f112e7e48195956f9a4df7668a5342523b27179cec958f363211ee11d0ec0e0e1b92ca007a61e8c9ac14e00229b9a7624850199e6667afa1a44db8f3c5de0a8eef0e6de050ac0ac633 +f931a3c12f0e3a5276f712b7706590ba02e14a97ff9b8ce3152af0fc4d9cdc690ea9bc4c82cb16c7d23136cbdab58fbec69880a88bca85c4214df01045082cbe9f4192e3e39c79896533c37dad9eb9e73c2643b9c0a704a4f93d81573537963d6b6e5140a24c702d9f26e06a2095de906daa8824172a6b39f563b7153907050b diff --git a/test/rsa_keys.py b/test/rsa_keys.py new file mode 100644 index 0000000..02b057d --- /dev/null +++ b/test/rsa_keys.py @@ -0,0 +1,152 @@ +from binascii import hexlify, unhexlify +from time import time +from struct import pack +from hashlib import sha1, sha256 +import string +from os import urandom + +def read_key_from_file(file): + f = open(file) + n_str = f.readline()[:-1] + e_str = f.readline()[:-1] + p_str = f.readline()[:-1] + q_str = f.readline()[:-1] + f.close() + e = int(e_str, 16) + p = int(p_str, 16) + q = int(q_str, 16) + n = int(n_str, 16) + if n != p * q: + raise ValueError("wrong key", p, q, n) + return (unhexlify(n_str), unhexlify(e_str), unhexlify(p_str), unhexlify(q_str), e, p, q, n) + +def calc_fpr(n,e): + timestamp = int(time()) + timestamp_data = pack('>I', timestamp) + m_len = 6 + 2 + 256 + 2 + 4 + m = '\x99' + pack('>H', m_len) + '\x04' + timestamp_data + '\x01' + \ + pack('>H', 2048) + n + pack('>H', 17) + e + fpr = sha1(m).digest() + return (fpr, timestamp_data) + +key = [ None, None, None ] +fpr = [ None, None, None ] +timestamp = [ None, None, None ] + +key[0] = read_key_from_file('rsa-sig.key') +key[1] = read_key_from_file('rsa-dec.key') +key[2] = read_key_from_file('rsa-aut.key') + +(fpr[0], timestamp[0]) = calc_fpr(key[0][0], key[0][1]) +(fpr[1], timestamp[1]) = calc_fpr(key[1][0], key[1][1]) +(fpr[2], timestamp[2]) = calc_fpr(key[2][0], key[2][1]) + +def build_privkey_template(openpgp_keyno, keyno): + n_str = key[keyno][0] + e_str = '\x00' + key[keyno][1] + p_str = key[keyno][2] + q_str = key[keyno][3] + + if openpgp_keyno == 1: + keyspec = '\xb6' + elif openpgp_keyno == 2: + keyspec = '\xb8' + else: + keyspec = '\xa4' + + key_template = '\x91\x04'+ '\x92\x81\x80' + '\x93\x81\x80' + + exthdr = keyspec + '\x00' + '\x7f\x48' + '\x08' + key_template + + suffix = '\x5f\x48' + '\x82\x01\x04' + + t = '\x4d' + '\x82\01\16' + exthdr + suffix + e_str + p_str + q_str + return t + +def build_privkey_template_for_remove(openpgp_keyno): + if openpgp_keyno == 1: + keyspec = '\xb6' + elif openpgp_keyno == 2: + keyspec = '\xb8' + else: + keyspec = '\xa4' + return '\x4d\02' + keyspec + '\0x00' + +def compute_digestinfo(msg): + digest = sha256(msg).digest() + prefix = '\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20' + return prefix + digest + +# egcd and modinv are from wikibooks +# https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm + +def egcd(a, b): + if a == 0: + return (b, 0, 1) + else: + g, y, x = egcd(b % a, a) + return (g, x - (b // a) * y, y) + +def modinv(a, m): + g, x, y = egcd(a, m) + if g != 1: + raise Exception('modular inverse does not exist') + else: + return x % m + +def pkcs1_pad_for_sign(digestinfo): + byte_repr = '\x00' + '\x01' + string.ljust('', 256 - 19 - 32 - 3, '\xff') \ + + '\x00' + digestinfo + return int(hexlify(byte_repr), 16) + +def pkcs1_pad_for_crypt(msg): + padlen = 256 - 3 - len(msg) + byte_repr = '\x00' + '\x02' \ + + string.replace(urandom(padlen),'\x00','\x01') + '\x00' + msg + return int(hexlify(byte_repr), 16) + +def compute_signature(keyno, digestinfo): + e = key[keyno][4] + p = key[keyno][5] + q = key[keyno][6] + n = key[keyno][7] + p1 = p - 1 + q1 = q - 1 + h = p1 * q1 + d = modinv(e, h) + dp = d % p1 + dq = d % q1 + qp = modinv(q, p) + + input = pkcs1_pad_for_sign(digestinfo) + t1 = pow(input, dp, p) + t2 = pow(input, dq, q) + t = ((t1 - t2) * qp) % p + sig = t2 + t * q + return sig + +def integer_to_bytes_256(i): + s = hex(i)[2:] + s = s.rstrip('L') + if len(s) & 1: + s = '0' + s + return string.rjust(unhexlify(s), 256, '\x00') + +def encrypt(keyno, plaintext): + e = key[keyno][4] + n = key[keyno][7] + m = pkcs1_pad_for_crypt(plaintext) + return '\x00' + integer_to_bytes_256(pow(m, e, n)) + +def encrypt_with_pubkey(pubkey_info, plaintext): + n = int(hexlify(pubkey_info[0]), 16) + e = int(hexlify(pubkey_info[1]), 16) + m = pkcs1_pad_for_crypt(plaintext) + return '\x00' + integer_to_bytes_256(pow(m, e, n)) + +def verify_signature(pubkey_info, digestinfo, sig): + n = int(hexlify(pubkey_info[0]), 16) + e = int(hexlify(pubkey_info[1]), 16) + di_pkcs1 = pow(sig,e,n) + m = pkcs1_pad_for_sign(digestinfo) + return di_pkcs1 == m diff --git a/tool/asm-thumb/README b/tool/asm-thumb/README new file mode 100644 index 0000000..e24b92a --- /dev/null +++ b/tool/asm-thumb/README @@ -0,0 +1,2 @@ +These assembler program are source code of program fragments in +stlinkv2.py. diff --git a/tool/asm-thumb/blank_check.S b/tool/asm-thumb/blank_check.S new file mode 100644 index 0000000..567ef23 --- /dev/null +++ b/tool/asm-thumb/blank_check.S @@ -0,0 +1,19 @@ +/* ARM Thumb Assembler code */ +// arm-none-eabi-gcc -Wa,-amhls=blank_check.lst -c blank_check.S + + .cpu cortex-m3 + .thumb + ldr r1, .START_ADDR + ldr r2, .END_ADDR +0: ldr r0, [r1] + add r0, r0, #1 + bne 1f + add r1, r1, #4 + cmp r1, r2 + bne 0b +1: bkpt #0x00 + // success: r0=0 + // fail: r0!=0 + .align 2 +.START_ADDR: .word 0x08000000 +.END_ADDR: .word 0x08020000 diff --git a/tool/asm-thumb/flash_write.S b/tool/asm-thumb/flash_write.S new file mode 100644 index 0000000..8f4b16c --- /dev/null +++ b/tool/asm-thumb/flash_write.S @@ -0,0 +1,39 @@ +/* ARM Thumb Assembler code */ +// arm-none-eabi-gcc -Wa,-amhls=flash_write.lst -c flash_write.S + +#define FLASH_CR_PG 0x0001 // == FLASH_SR_BSY +#define FLASH_CR_ERRORS 0x0014 // == PGERR | WRPRTERR +#define FLASH_SR_BSY 0x0001 + +#define FLASH_SR_OFFSET 0x0c +#define FLASH_CR_OFFSET 0x10 + +#define COUNT 0x1000 + + .cpu cortex-m3 + .thumb + movw r2, #COUNT + ldr r0, .SRC_ADDR + ldr r1, .TARGET_ADDR + ldr r4, .FLASH_BASE_ADDR + mov r5, #FLASH_CR_PG + mov r6, #FLASH_CR_ERRORS + mov r7, #0 + str r5, [r4, #FLASH_CR_OFFSET] +0: ldrh r3, [r0, r7] + strh r3, [r1, r7] +1: ldr r3, [r4, #FLASH_SR_OFFSET] + tst r3, r5 + bne 1b + tst r3, r6 + bne 2f + add r7, r7, #0x02 + cmp r7, r2 + bne 0b +2: mov r7, #0 + str r7, [r4, #FLASH_CR_OFFSET] + bkpt #0x00 + .align 2 +.FLASH_BASE_ADDR: .word 0x40022000 +.SRC_ADDR: .word 0x20000038 +.TARGET_ADDR: .word 0x08000000 diff --git a/tool/asm-thumb/opt_bytes_write.S b/tool/asm-thumb/opt_bytes_write.S new file mode 100644 index 0000000..dad89bb --- /dev/null +++ b/tool/asm-thumb/opt_bytes_write.S @@ -0,0 +1,29 @@ +/* ARM Thumb Assembler code */ +// arm-none-eabi-gcc -Wa,-amhls=opt_bytes_write.lst -c opt_bytes_write.S + +#define FLASH_CR_OPTPG 0x0010 +#define FLASH_SR_BSY 0x0001 + +#define FLASH_SR_OFFSET 0x0c +#define FLASH_CR_OFFSET 0x10 + +#define OB_RDP_UNLOCK 0x00a5 + + .cpu cortex-m3 + .thumb + movw r0, #OB_RDP_UNLOCK + ldr r1, .TARGET_ADDR + ldr r2, .FLASH_BASE_ADDR + mov r3, #FLASH_CR_OPTPG + mov r4, #FLASH_SR_BSY + str r3, [r2, #FLASH_CR_OFFSET] + strh r0, [r1] +1: ldr r0, [r2, #FLASH_SR_OFFSET] + tst r0, r4 + bne 1b + mov r0, #0 + str r0, [r2, #FLASH_CR_OFFSET] + bkpt #0x00 + .align 2 +.FLASH_BASE_ADDR: .word 0x40022000 +.TARGET_ADDR: .word 0x1FFFF800 diff --git a/tool/dfuse.py b/tool/dfuse.py index 722f217..d95750e 100755 --- a/tool/dfuse.py +++ b/tool/dfuse.py @@ -4,7 +4,7 @@ dfuse.py - DFU (Device Firmware Upgrade) tool for STM32 Processor. "SE" in DfuSe stands for "STmicroelectronics Extention". -Copyright (C) 2010 Free Software Initiative of Japan +Copyright (C) 2010, 2011 Free Software Initiative of Japan Author: NIIBE Yutaka This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -94,7 +94,7 @@ STATE_DFU_ERROR = 0x0a def get_four_bytes (v): return [ v % 256, (v >> 8)%256, (v >> 16)%256, (v >> 24) ] -class DFU_STM32: +class DFU_STM32(object): def __init__(self, device, configuration, interface): """ __init__(device, configuration, interface) -> None @@ -208,10 +208,23 @@ class DFU_STM32: # First, erase pages sys.stdout.write("Erasing: ") sys.stdout.flush() + last_addr = 0 for start_addr in sorted(ih.memory.keys()): data = ih.memory[start_addr] end_addr = start_addr + len(data) addr = start_addr & 0xfffffc00 + if not last_addr == 0: + i = 0 + if last_addr > addr: + addr = last_addr + else: + while last_addr < addr: + self.dfuse_erase(last_addr) + if i & 0x03 == 0x03: + sys.stdout.write(".") + sys.stdout.flush() + last_addr += 1024 + i += 1 i = 0 while addr < end_addr: self.dfuse_erase(addr) @@ -220,20 +233,32 @@ class DFU_STM32: sys.stdout.flush() addr += 1024 i += 1 + last_addr = addr sys.stdout.write("\n") sys.stdout.flush() # Then, write pages sys.stdout.write("Writing: ") sys.stdout.flush() + last_addr = 0 for start_addr in sorted(ih.memory.keys()): data = ih.memory[start_addr] end_addr = start_addr + len(data) addr = start_addr & 0xfffffc00 - # XXX: data should be 1-KiB aligned - if addr != start_addr: - raise ValueError, "padding is not supported yet" - self.dfuse_set_address_pointer(addr) + if not last_addr == 0: + i = 0 + while last_addr < addr: + if i & 0x03 == 0x03: + sys.stdout.write(".") + sys.stdout.flush() + last_addr += 1024 + i += 1 i = 0 + if addr != start_addr: + self.dfuse_set_address_pointer(start_addr) + self.dfuse_write_memory(data[0:(addr + 1024 - start_addr)]) + data = data[(addr + 1024 - start_addr):] + addr += 1024 + self.dfuse_set_address_pointer(addr) while addr < end_addr: self.dfuse_write_memory(data[i*1024:(i+1)*1024]) if i & 0x03 == 0x03: @@ -241,6 +266,7 @@ class DFU_STM32: sys.stdout.flush() addr += 1024 i += 1 + last_addr = addr if self.__protocol == DFU_STM32PROTOCOL_0: # 0-length write at the end self.ll_download_block(self.__blocknum, None) @@ -268,13 +294,33 @@ class DFU_STM32: # Read pages sys.stdout.write("Reading: ") sys.stdout.flush() + last_addr = 0 for start_addr in sorted(ih.memory.keys()): data = ih.memory[start_addr] end_addr = start_addr + len(data) addr = start_addr & 0xfffffc00 - # XXX: data should be 1-KiB aligned + if not last_addr == 0: + i = 0 + while last_addr < addr: + if i & 0x03 == 0x03: + sys.stdout.write(".") + sys.stdout.flush() + last_addr += 1024 + i += 1 if addr != start_addr: - raise ValueError, "padding is not supported yet" + self.dfuse_set_address_pointer(addr) + self.ll_clear_status() + self.ll_clear_status() + block = self.dfuse_read_memory() + j = 0 + for c in data[0:(addr + 1024 - start_addr)]: + if (ord(c)&0xff) != block[j + start_addr - addr]: + raise ValueError, "verify failed at %08x" % (addr + i*1024+j) + j += 1 + data = data[(addr + 1024 - start_addr):] + addr += 1024 + self.ll_clear_status() + self.ll_clear_status() self.dfuse_set_address_pointer(addr) self.ll_clear_status() self.ll_clear_status() @@ -291,6 +337,7 @@ class DFU_STM32: sys.stdout.flush() addr += 1024 i += 1 + last_addr = addr self.ll_clear_status() self.ll_clear_status() self.ll_clear_status() diff --git a/tool/get_raw_public_key.py b/tool/get_raw_public_key.py new file mode 100755 index 0000000..fb1272f --- /dev/null +++ b/tool/get_raw_public_key.py @@ -0,0 +1,32 @@ +#! /usr/bin/python + +import sys, binascii +from subprocess import check_output + +def get_gpg_public_key(keygrip): + result = check_output(["gpg-connect-agent", "READKEY %s" % keygrip, "/bye"]) + key = "" + while True: + i = result.find('%') + if i < 0: + key += result + break + hex_str = result[i+1:i+3] + key += result[0:i] + key += chr(int(hex_str,16)) + result = result[i+3:] + + pos = key.index("D (10:public-key(3:rsa(1:n257:") + 31 # skip NUL too + pos_last = key.index(")(1:e3:") + key = key[pos:pos_last] + if len(key) != 256: + raise ValueError, binascii.hexlify(key) + return key + +if __name__ == '__main__': + keygrip = sys.argv[1] + k = get_gpg_public_key(keygrip) + shorthand = keygrip[0:8] + ".bin" + f = open(shorthand,"w") + f.write(k) + f.close() diff --git a/tool/gnuk_put_binary.py b/tool/gnuk_put_binary.py index 07a86e9..a97a2d9 100755 --- a/tool/gnuk_put_binary.py +++ b/tool/gnuk_put_binary.py @@ -2,9 +2,9 @@ """ gnuk_put_binary.py - a tool to put binary to Gnuk Token -This tool is for importing certificate, updating random number, etc. +This tool is for importing certificate, writing serial number, etc. -Copyright (C) 2011 Free Software Initiative of Japan +Copyright (C) 2011, 2012 Free Software Initiative of Japan Author: NIIBE Yutaka This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -43,11 +43,33 @@ class GnukToken(object): cardservice = cardrequest.waitforcard() self.connection = cardservice.connection + def cmd_get_response(self, expected_len): + result = [] + while True: + apdu = [0x00, 0xc0, 0x00, 0x00, expected_len] + response, sw1, sw2 = self.connection.transmit(apdu) + result += response + if sw1 == 0x90 and sw2 == 0x00: + return result + elif sw1 != 0x61: + raise ValueError, ("%02x%02x" % (sw1, sw2)) + else: + expected_len = sw2 + def cmd_verify(self, who, passwd): - apdu = [0x00, 0x20, 0x00, 0x80+who, 0, 0, len(passwd)] + s2l(passwd) + apdu = [0x00, 0x20, 0x00, 0x80+who, len(passwd)] + s2l(passwd) response, sw1, sw2 = self.connection.transmit(apdu) if not (sw1 == 0x90 and sw2 == 0x00): - raise ValueError, "cmd_verify" + raise ValueError, ("%02x%02x" % (sw1, sw2)) + + def cmd_read_binary(self, fileid): + apdu = [0x00, 0xb0, 0x80+fileid, 0x00] + response, sw1, sw2 = self.connection.transmit(apdu) + if sw1 == 0x61: + response = self.cmd_get_response(sw2) + elif not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%02x%02x" % (sw1, sw2)) + return response def cmd_write_binary(self, fileid, data, is_update): count = 0 @@ -59,29 +81,43 @@ class GnukToken(object): while count*256 < data_len: if count == 0: d = data[:256] - apdu = [0x00, ins, 0x80+fileid, 0x00, 0, len(d)>>8, len(d)&0xff] + s2l(d) + if len(d) <= 255: + apdu = [0x00, ins, 0x80+fileid, 0x00, len(d)] + s2l(d) + else: + apdu0 = [0x10, ins, 0x80+fileid, 0x00, 255] + s2l(d[:255]) + response, sw1, sw2 = self.connection.transmit(apdu0) + apdu = [0x00, ins, 0x80+fileid, 0x00, 1 ] + s2l(d[255:]) else: d = data[256*count:256*(count+1)] - apdu = [0x00, ins, count, 0x00, 0, len(d)>>8, len(d)&0xff] + s2l(d) + if len(d) <= 255: + apdu = [0x00, ins, count, 0x00, len(d)] + s2l(d) + else: + apdu0 = [0x10, ins, count, 0x00, 255] + s2l(d[:255]) + response, sw1, sw2 = self.connection.transmit(apdu0) + apdu = [0x00, ins, count, 0x00, 1] + s2l(d[255:]) response, sw1, sw2 = self.connection.transmit(apdu) if not (sw1 == 0x90 and sw2 == 0x00): if is_update: - raise ValueError, "cmd_update_binary" + raise ValueError, ("update failure: %02x%02x" % (sw1, sw2)) else: - raise ValueError, "cmd_write_binary" + raise ValueError, ("write failure: %02x%02x" % (sw1, sw2)) count += 1 def cmd_select_openpgp(self): - apdu = [0x00, 0xa4, 0x04, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ] + apdu = [0x00, 0xa4, 0x04, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01] response, sw1, sw2 = self.connection.transmit(apdu) - if not (sw1 == 0x90 and sw2 == 0x00): - raise ValueError, "cmd_select_openpgp" + if sw1 == 0x61: + response = self.cmd_get_response(sw2) + elif not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%02x%02x" % (sw1, sw2)) def cmd_get_data(self, tagh, tagl): apdu = [0x00, 0xca, tagh, tagl] response, sw1, sw2 = self.connection.transmit(apdu) - if not (sw1 == 0x90 and sw2 == 0x00): - raise ValueError, "cmd_get_data" + if sw1 == 0x61: + response = self.cmd_get_response(sw2) + elif not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%02x%02x" % (sw1, sw2)) return response def compare(data_original, data_in_device): @@ -103,17 +139,19 @@ def main(fileid, is_update, data, passwd): gnuk.cmd_verify(BY_ADMIN, passwd) gnuk.cmd_write_binary(fileid, data, is_update) + gnuk.cmd_select_openpgp() if fileid == 0: - gnuk.cmd_select_openpgp() - data_in_device = gnuk.cmd_get_data(0x7f, 0x21) - compare(data[:-2], data_in_device) - elif fileid == 2: - gnuk.cmd_select_openpgp() data_in_device = gnuk.cmd_get_data(0x00, 0x4f) for d in data_in_device: print "%02x" % d, print compare(data, data_in_device[8:]) + elif fileid >= 1 and fileid <= 4: + data_in_device = gnuk.cmd_read_binary(fileid) + compare(data, data_in_device) + elif fileid == 5: + data_in_device = gnuk.cmd_get_data(0x7f, 0x21) + compare(data, data_in_device) gnuk.connection.disconnect() return 0 @@ -123,7 +161,7 @@ if __name__ == '__main__': passwd = DEFAULT_PW3 if sys.argv[1] == '-p': from getpass import getpass - passwd = getpass("Admin password:") + passwd = getpass("Admin password: ") sys.argv.pop(1) if sys.argv[1] == '-u': is_update = True @@ -131,7 +169,7 @@ if __name__ == '__main__': else: is_update = False if sys.argv[1] == '-s': - fileid = 2 # serial number + fileid = 0 # serial number filename = sys.argv[2] f = open(filename) email = os.environ['EMAIL'] @@ -146,25 +184,19 @@ if __name__ == '__main__': exit(1) print "Writing serial number" data = binascii.unhexlify(serial_data_hex) - elif sys.argv[1] == '-r': - fileid = 1 # Random number bits - if len(sys.argv) == 3: - filename = sys.argv[2] - f = open(filename) - else: - filename = stdin - f = sys.stdin + elif sys.argv[1] == '-k': # firmware update key + keyno = sys.argv[2] + fileid = 1 + int(keyno) + filename = sys.argv[3] + f = open(filename) data = f.read() f.close() - print "%s: %d" % (filename, len(data)) - print "Updating random bits" else: - fileid = 0 # Card holder certificate + fileid = 5 # Card holder certificate filename = sys.argv[1] f = open(filename) data = f.read() f.close() print "%s: %d" % (filename, len(data)) - data += "\x90\x00" print "Updating card holder certificate" main(fileid, is_update, data, passwd) diff --git a/tool/gnuk_put_binary_libusb.py b/tool/gnuk_put_binary_libusb.py index d4a1e87..3899c4c 100755 --- a/tool/gnuk_put_binary_libusb.py +++ b/tool/gnuk_put_binary_libusb.py @@ -2,9 +2,9 @@ """ gnuk_put_binary.py - a tool to put binary to Gnuk Token -This tool is for importing certificate, updating random number, etc. +This tool is for importing certificate, writing serial number, etc. -Copyright (C) 2011 Free Software Initiative of Japan +Copyright (C) 2011, 2012 Free Software Initiative of Japan Author: NIIBE Yutaka This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -23,239 +23,63 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from intel_hex import * from struct import * import sys, time, os, binascii, string +from gnuk_token import * # INPUT: binary file # Assume only single CCID device is attached to computer, and it's Gnuk Token -import usb +DEFAULT_PW3 = "12345678" +BY_ADMIN = 3 -# USB class, subclass, protocol -CCID_CLASS = 0x0B -CCID_SUBCLASS = 0x00 -CCID_PROTOCOL_0 = 0x00 - -def icc_compose(msg_type, data_len, slot, seq, param, data): - return pack('BBBB', cls, ins, p1, p2) - else: - return pack('>BBBBBh', cls, ins, p1, p2, 0, data_len) + data - -# This class only supports Gnuk (for now) -class gnuk_token: - def __init__(self, device, configuration, interface): - """ - __init__(device, configuration, interface) -> None - Initialize the device. - device: usb.Device object. - configuration: configuration number. - interface: usb.Interface object representing the interface and altenate setting. - """ - if interface.interfaceClass != CCID_CLASS: - raise ValueError, "Wrong interface class" - if interface.interfaceSubClass != CCID_SUBCLASS: - raise ValueError, "Wrong interface sub class" - self.__devhandle = device.open() +def main(fileid, is_update, data, passwd): + gnuk = None + for (dev, config, intf) in gnuk_devices(): try: - self.__devhandle.setConfiguration(configuration) + gnuk = gnuk_token(dev, config, intf) + print "Device: ", dev.filename + print "Configuration: ", config.value + print "Interface: ", intf.interfaceNumber + break except: pass - self.__devhandle.claimInterface(interface) - self.__devhandle.setAltInterface(interface) - - self.__intf = interface.interfaceNumber - self.__alt = interface.alternateSetting - self.__conf = configuration - - self.__bulkout = 2 - self.__bulkin = 0x81 - - self.__timeout = 10000 - self.__seq = 0 - - def icc_get_result(self): - msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout) - if len(msg) < 10: - print msg - raise ValueError, "icc_get_result" - msg_type = msg[0] - data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24) - slot = msg[5] - seq = msg[6] - status = msg[7] - error = msg[8] - chain = msg[9] - data = msg[10:] - # XXX: check msg_type, data_len, slot, seq, error - return (status, chain, data) - - def icc_get_status(self): - msg = icc_compose(0x65, 0, 0, self.__seq, 0, "") - self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) - self.__seq += 1 - status, chain, data = self.icc_get_result() - # XXX: check chain, data - return status - - def icc_power_on(self): - msg = icc_compose(0x62, 0, 0, self.__seq, 0, "") - self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) - self.__seq += 1 - status, chain, data = self.icc_get_result() - # XXX: check status, chain - return data # ATR - - def icc_power_off(self): - msg = icc_compose(0x63, 0, 0, self.__seq, 0, "") - self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) - self.__seq += 1 - status, chain, data = self.icc_get_result() - # XXX: check chain, data - return status - - def icc_send_data_block(self, data): - msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data) - self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) - self.__seq += 1 - return self.icc_get_result() - - def icc_send_cmd(self, data): - status, chain, data_rcv = self.icc_send_data_block(data) - if chain == 0: - return data_rcv - elif chain == 1: - d = data_rcv - while True: - msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "") - self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) - self.__seq += 1 - status, chain, data_rcv = self.icc_get_result() - # XXX: check status - d += data_rcv - if chain == 2: - break - elif chain == 3: - continue - else: - raise ValueError, "icc_send_cmd chain" - return d - else: - raise ValueError, "icc_send_cmd" - - def cmd_verify(self, who, passwd): - cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd) - sw = self.icc_send_cmd(cmd_data) - if len(sw) != 2: - raise ValueError, "cmd_verify" - if not (sw[0] == 0x90 and sw[1] == 0x00): - raise ValueError, "cmd_verify" - - def cmd_write_binary(self, fileid, data): - count = 0 - data_len = len(data) - while count*256 < data_len: - if count == 0: - cmd_data = iso7816_compose(0xd0, 0x80+fileid, 0x00, data[:256]) - else: - cmd_data = iso7816_compose(0xd0, count, 0x00, data[256*count:256*(count+1)]) - sw = self.icc_send_cmd(cmd_data) - if len(sw) != 2: - raise ValueError, "cmd_write_binary" - if not (sw[0] == 0x90 and sw[1] == 0x00): - raise ValueError, "cmd_write_binary" - count += 1 - - def cmd_update_binary(self, fileid, data): - count = 0 - data_len = len(data) - while count*256 < data_len: - if count == 0: - cmd_data = iso7816_compose(0xd6, 0x80+fileid, 0x00, data[:256]) - else: - cmd_data = iso7816_compose(0xd6, count, 0x00, data[256*count:256*(count+1)]) - sw = self.icc_send_cmd(cmd_data) - if len(sw) != 2: - raise ValueError, "cmd_update_binary" - if not (sw[0] == 0x90 and sw[1] == 0x00): - raise ValueError, "cmd_update_binary" - count += 1 - - def cmd_select_openpgp(self): - cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01") - sw = self.icc_send_cmd(cmd_data) - if len(sw) != 2: - raise ValueError, "cmd_select_openpgp" - if not (sw[0] == 0x90 and sw[1] == 0x00): - raise ValueError, "cmd_select_openpgp" - - def cmd_get_data(self, tagh, tagl): - cmd_data = iso7816_compose(0xca, tagh, tagl, "") - result = self.icc_send_cmd(cmd_data) - sw = result[-2:] - if not (sw[0] == 0x90 and sw[1] == 0x00): - raise ValueError, "cmd_get_data" - return result[:-2] - -def compare(data_original, data_in_device): - i = 0 - for d in data_original: - if ord(d) != data_in_device[i]: - raise ValueError, "verify failed at %08x" % i - i += 1 - -def get_device(): - busses = usb.busses() - for bus in busses: - devices = bus.devices - for dev in devices: - for config in dev.configurations: - for intf in config.interfaces: - for alt in intf: - if alt.interfaceClass == CCID_CLASS and \ - alt.interfaceSubClass == CCID_SUBCLASS and \ - alt.interfaceProtocol == CCID_PROTOCOL_0: - return dev, config, alt - raise ValueError, "Device not found" - -def main(fileid, is_update, data): - dev, config, intf = get_device() - print "Device: ", dev.filename - print "Configuration: ", config.value - print "Interface: ", intf.interfaceNumber - icc = gnuk_token(dev, config, intf) - if icc.icc_get_status() == 2: + if gnuk.icc_get_status() == 2: raise ValueError, "No ICC present" - elif icc.icc_get_status() == 1: - icc.icc_power_on() - icc.cmd_verify(3, "12345678") - if is_update: - icc.cmd_update_binary(fileid, data) - else: - icc.cmd_write_binary(fileid, data) - icc.cmd_select_openpgp() + elif gnuk.icc_get_status() == 1: + gnuk.icc_power_on() + gnuk.cmd_verify(BY_ADMIN, passwd) + gnuk.cmd_write_binary(fileid, data, is_update) + gnuk.cmd_select_openpgp() if fileid == 0: - data = data[:-2] - data_in_device = icc.cmd_get_data(0x7f, 0x21) + data_in_device = gnuk.cmd_get_data(0x00, 0x4f) + for d in data_in_device: + print "%02x" % ord(d), + print + compare(data + '\x00\x00', data_in_device[8:]) + elif fileid >= 1 and fileid <= 4: + data_in_device = gnuk.cmd_read_binary(fileid) compare(data, data_in_device) - icc.icc_power_off() + else: + data_in_device = gnuk.cmd_get_data(0x7f, 0x21) + compare(data, data_in_device) + gnuk.icc_power_off() return 0 if __name__ == '__main__': + passwd = DEFAULT_PW3 + if sys.argv[1] == '-p': + from getpass import getpass + passwd = getpass("Admin password: ") + sys.argv.pop(1) if sys.argv[1] == '-u': is_update = True sys.argv.pop(1) else: is_update = False if sys.argv[1] == '-s': - fileid = 2 # serial number + fileid = 0 # serial number filename = sys.argv[2] f = open(filename) email = os.environ['EMAIL'] @@ -270,25 +94,19 @@ if __name__ == '__main__': exit(1) print "Writing serial number" data = binascii.unhexlify(serial_data_hex) - elif sys.argv[1] == '-r': - fileid = 1 # Random number bits - if len(sys.argv) == 3: - filename = sys.argv[2] - f = open(filename) - else: - filename = stdin - f = sys.stdin + elif sys.argv[1] == '-k': # firmware update key + keyno = sys.argv[2] + fileid = 1 + int(keyno) + filename = sys.argv[3] + f = open(filename) data = f.read() f.close() - print "%s: %d" % (filename, len(data)) - print "Updating random bits" else: - fileid = 0 # Card holder certificate + fileid = 5 # Card holder certificate filename = sys.argv[1] f = open(filename) data = f.read() f.close() print "%s: %d" % (filename, len(data)) - data += "\x90\x00" print "Updating card holder certificate" - main(fileid, is_update, data) + main(fileid, is_update, data, passwd) diff --git a/tool/gnuk_remove_keys.py b/tool/gnuk_remove_keys.py new file mode 100755 index 0000000..b8e0690 --- /dev/null +++ b/tool/gnuk_remove_keys.py @@ -0,0 +1,112 @@ +#! /usr/bin/python + +""" +gnuk_remove_keys.py - a tool to remove keys in Gnuk Token + +Copyright (C) 2012 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 . +""" + +import sys, os, string + +# Assume only single CCID device is attached to computer and it's Gnuk Token + +from smartcard.CardType import AnyCardType +from smartcard.CardRequest import CardRequest +from smartcard.util import toHexString + +def s2l(s): + return [ ord(c) for c in s ] + +class GnukToken(object): + def __init__(self): + cardtype = AnyCardType() + cardrequest = CardRequest(timeout=1, cardType=cardtype) + cardservice = cardrequest.waitforcard() + self.connection = cardservice.connection + + def cmd_get_response(self, expected_len): + apdu = [0x00, 0xc0, 0x00, 0x00, expected_len] + response, sw1, sw2 = self.connection.transmit(apdu) + if not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%02x%02x" % (sw1, sw2)) + return response + + def cmd_verify(self, who, passwd): + apdu = [0x00, 0x20, 0x00, 0x80+who, len(passwd)] + s2l(passwd) + response, sw1, sw2 = self.connection.transmit(apdu) + if not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%02x%02x" % (sw1, sw2)) + + def cmd_select_openpgp(self): + apdu = [0x00, 0xa4, 0x04, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01] + response, sw1, sw2 = self.connection.transmit(apdu) + if sw1 == 0x61: + response = self.cmd_get_response(sw2) + elif not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%02x%02x" % (sw1, sw2)) + + def cmd_put_data_remove(self, tagh, tagl): + apdu = [0x00, 0xda, tagh, tagl, 0] + response, sw1, sw2 = self.connection.transmit(apdu) + return response + + def cmd_put_data_key_import_remove(self, keyno): + if keyno == 1: + keyspec = 0xb6 # SIG + elif keyno == 2: + keyspec = 0xb8 # DEC + else: + keyspec = 0xa4 # AUT + apdu = [0x00, 0xdb, 0x3f, 0xff, 4, 0x4d, 0x02, keyspec, 0x00] + response, sw1, sw2 = self.connection.transmit(apdu) + return response + +DEFAULT_PW3 = "12345678" +BY_ADMIN = 3 + +def main(passwd): + gnuk = GnukToken() + + gnuk.connection.connect() + print "Token:", gnuk.connection.getReader() + print "ATR:", toHexString( gnuk.connection.getATR() ) + + gnuk.cmd_verify(BY_ADMIN, passwd) + gnuk.cmd_select_openpgp() + gnuk.cmd_put_data_remove(0x00, 0xc7) # FP_SIG + gnuk.cmd_put_data_remove(0x00, 0xce) # KGTIME_SIG + gnuk.cmd_put_data_key_import_remove(1) + gnuk.cmd_put_data_remove(0x00, 0xc8) # FP_DEC + gnuk.cmd_put_data_remove(0x00, 0xcf) # KGTIME_DEC + gnuk.cmd_put_data_key_import_remove(2) + gnuk.cmd_put_data_remove(0x00, 0xc9) # FP_AUT + gnuk.cmd_put_data_remove(0x00, 0xd0) # KGTIME_AUT + gnuk.cmd_put_data_key_import_remove(3) + + gnuk.connection.disconnect() + return 0 + + +if __name__ == '__main__': + passwd = DEFAULT_PW3 + if len(sys.argv) > 1 and sys.argv[1] == '-p': + from getpass import getpass + passwd = getpass("Admin password: ") + sys.argv.pop(1) + main(passwd) diff --git a/tool/gnuk_remove_keys_libusb.py b/tool/gnuk_remove_keys_libusb.py new file mode 100755 index 0000000..d04b432 --- /dev/null +++ b/tool/gnuk_remove_keys_libusb.py @@ -0,0 +1,70 @@ +#! /usr/bin/python + +""" +gnuk_remove_keys_libusb.py - a tool to remove keys in Gnuk Token + +Copyright (C) 2012 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 . +""" + +import sys, os, string + +from gnuk_token import * + +# Assume only single CCID device is attached to computer and it's Gnuk Token + +DEFAULT_PW3 = "12345678" +BY_ADMIN = 3 + +def main(passwd): + gnuk = None + for (dev, config, intf) in gnuk_devices(): + try: + gnuk = gnuk_token(dev, config, intf) + print "Device: ", dev.filename + print "Configuration: ", config.value + print "Interface: ", intf.interfaceNumber + break + except: + pass + if gnuk.icc_get_status() == 2: + raise ValueError, "No ICC present" + elif gnuk.icc_get_status() == 1: + gnuk.icc_power_on() + gnuk.cmd_verify(BY_ADMIN, passwd) + gnuk.cmd_select_openpgp() + gnuk.cmd_put_data_remove(0x00, 0xc7) # FP_SIG + gnuk.cmd_put_data_remove(0x00, 0xce) # KGTIME_SIG + gnuk.cmd_put_data_key_import_remove(1) + gnuk.cmd_put_data_remove(0x00, 0xc8) # FP_DEC + gnuk.cmd_put_data_remove(0x00, 0xcf) # KGTIME_DEC + gnuk.cmd_put_data_key_import_remove(2) + gnuk.cmd_put_data_remove(0x00, 0xc9) # FP_AUT + gnuk.cmd_put_data_remove(0x00, 0xd0) # KGTIME_AUT + gnuk.cmd_put_data_key_import_remove(3) + gnuk.icc_power_off() + return 0 + + +if __name__ == '__main__': + passwd = DEFAULT_PW3 + if len(sys.argv) > 1 and sys.argv[1] == '-p': + from getpass import getpass + passwd = getpass("Admin password: ") + sys.argv.pop(1) + main(passwd) diff --git a/tool/gnuk_token.py b/tool/gnuk_token.py new file mode 100644 index 0000000..2de473f --- /dev/null +++ b/tool/gnuk_token.py @@ -0,0 +1,617 @@ +""" +gnuk_token.py - a library for Gnuk Token + +Copyright (C) 2011, 2012 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 . +""" + +from struct import * +import string, binascii +import usb, time + +# USB class, subclass, protocol +CCID_CLASS = 0x0B +CCID_SUBCLASS = 0x00 +CCID_PROTOCOL_0 = 0x00 + +def icc_compose(msg_type, data_len, slot, seq, param, data): + return pack('BBBB', cls, ins, p1, p2) + else: + return pack('>BBBBB', cls, ins, p1, p2, data_len) + data + +def list_to_string(l): + return string.join([chr(c) for c in l], '') + +# This class only supports Gnuk (for now) +class gnuk_token(object): + def __init__(self, device, configuration, interface): + """ + __init__(device, configuration, interface) -> None + Initialize the device. + device: usb.Device object. + configuration: configuration number. + interface: usb.Interface object representing the interface and altenate setting. + """ + if interface.interfaceClass != CCID_CLASS: + raise ValueError("Wrong interface class") + if interface.interfaceSubClass != CCID_SUBCLASS: + raise ValueError("Wrong interface sub class") + self.__devhandle = device.open() + try: + self.__devhandle.setConfiguration(configuration) + except: + pass + self.__devhandle.claimInterface(interface) + self.__devhandle.setAltInterface(interface) + + self.__intf = interface.interfaceNumber + self.__alt = interface.alternateSetting + self.__conf = configuration + + self.__bulkout = 1 + self.__bulkin = 0x81 + + self.__timeout = 10000 + self.__seq = 0 + + def get_string(self, num): + return self.__devhandle.getString(num, 512) + + def increment_seq(self): + self.__seq = (self.__seq + 1) & 0xff + + def reset_device(self): + try: + self.__devhandle.reset() + except: + pass + + def release_gnuk(self): + self.__devhandle.releaseInterface() + + def stop_gnuk(self): + self.__devhandle.releaseInterface() + self.__devhandle.setConfiguration(0) + return + + def mem_info(self): + mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, + value = 0, index = 0, buffer = 8, + timeout = 10) + start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0] + end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4] + return (start, end) + + def download(self, start, data): + addr = start + addr_end = (start + len(data)) & 0xffffff00 + i = (addr - 0x20000000) / 0x100 + j = 0 + print "start %08x" % addr + print "end %08x" % addr_end + while addr < addr_end: + print "# %08x: %d : %d" % (addr, i, 256) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = i, index = 0, + buffer = data[j*256:j*256+256], + timeout = 10) + i = i+1 + j = j+1 + addr = addr + 256 + residue = len(data) % 256 + if residue != 0: + print "# %08x: %d : %d" % (addr, i, residue) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = i, index = 0, + buffer = data[j*256:], + timeout = 10) + + def execute(self, last_addr): + i = (last_addr - 0x20000000) / 0x100 + o = (last_addr - 0x20000000) % 0x100 + self.__devhandle.controlMsg(requestType = 0x40, request = 2, + value = i, index = o, buffer = None, + timeout = 10) + + def icc_get_result(self): + msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout) + if len(msg) < 10: + print msg + raise ValueError("icc_get_result") + msg_type = msg[0] + data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24) + slot = msg[5] + seq = msg[6] + status = msg[7] + error = msg[8] + chain = msg[9] + data = msg[10:] + # XXX: check msg_type, data_len, slot, seq, error + return (status, chain, data) + + def icc_get_status(self): + msg = icc_compose(0x65, 0, 0, self.__seq, 0, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.increment_seq() + status, chain, data = self.icc_get_result() + # XXX: check chain, data + return status + + def icc_power_on(self): + msg = icc_compose(0x62, 0, 0, self.__seq, 0, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.increment_seq() + status, chain, data = self.icc_get_result() + # XXX: check status, chain + self.atr = list_to_string(data) # ATR + return self.atr + + def icc_power_off(self): + msg = icc_compose(0x63, 0, 0, self.__seq, 0, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.increment_seq() + status, chain, data = self.icc_get_result() + # XXX: check chain, data + return status + + def icc_send_data_block(self, data): + msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data) + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.increment_seq() + return self.icc_get_result() + + def icc_send_cmd(self, data): + status, chain, data_rcv = self.icc_send_data_block(data) + if chain == 0: + while status == 0x80: + status, chain, data_rcv = self.icc_get_result() + return data_rcv + elif chain == 1: + d = data_rcv + while True: + msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.increment_seq() + status, chain, data_rcv = self.icc_get_result() + # XXX: check status + d += data_rcv + if chain == 2: + break + elif chain == 3: + continue + else: + raise ValueError("icc_send_cmd chain") + return d + else: + raise ValueError("icc_send_cmd") + + def cmd_get_response(self, expected_len): + result = [] + while True: + cmd_data = iso7816_compose(0xc0, 0x00, 0x00, '') + pack('>B', expected_len) + response = self.icc_send_cmd(cmd_data) + result += response[:-2] + sw = response[-2:] + if sw[0] == 0x90 and sw[1] == 0x00: + return list_to_string(result) + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + else: + expected_len = sw[1] + + def cmd_verify(self, who, passwd): + cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return True + + def cmd_read_binary(self, fileid): + cmd_data = iso7816_compose(0xb0, 0x80+fileid, 0x00, '') + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + + def cmd_write_binary(self, fileid, data, is_update): + count = 0 + data_len = len(data) + if is_update: + ins = 0xd6 + else: + ins = 0xd0 + while count*256 < data_len: + if count == 0: + if len(data) < 128: + cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128]) + cmd_data1 = None + else: + cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128], 0x10) + cmd_data1 = iso7816_compose(ins, 0x80+fileid, 0x00, data[128:256]) + else: + if len(data[256*count:256*count+128]) < 128: + cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128]) + cmd_data1 = None + else: + cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128], 0x10) + cmd_data1 = iso7816_compose(ins, count, 0x00, data[256*count+128:256*(count+1)]) + sw = self.icc_send_cmd(cmd_data0) + if len(sw) != 2: + raise ValueError("cmd_write_binary 0") + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("cmd_write_binary 0", "%02x%02x" % (sw[0], sw[1])) + if cmd_data1: + sw = self.icc_send_cmd(cmd_data1) + if len(sw) != 2: + raise ValueError("cmd_write_binary 1", sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("cmd_write_binary 1", "%02x%02x" % (sw[0], sw[1])) + count += 1 + + def cmd_select_openpgp(self): + cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01") + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return True + + def cmd_get_data(self, tagh, tagl): + cmd_data = iso7816_compose(0xca, tagh, tagl, "") + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if sw[0] == 0x90 and sw[1] == 0x00: + return "" + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + + def cmd_change_reference_data(self, who, data): + cmd_data = iso7816_compose(0x24, 0x00, 0x80+who, data) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return True + + def cmd_put_data(self, tagh, tagl, content): + cmd_data = iso7816_compose(0xda, tagh, tagl, content) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return True + + def cmd_put_data_odd(self, tagh, tagl, content): + cmd_data0 = iso7816_compose(0xdb, tagh, tagl, content[:128], 0x10) + cmd_data1 = iso7816_compose(0xdb, tagh, tagl, content[128:]) + sw = self.icc_send_cmd(cmd_data0) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + sw = self.icc_send_cmd(cmd_data1) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return True + + def cmd_reset_retry_counter(self, how, data): + cmd_data = iso7816_compose(0x2c, how, 0x00, data) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return True + + def cmd_pso(self, p1, p2, data): + cmd_data = iso7816_compose(0x2a, p1, p2, data) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if sw[0] == 0x90 and sw[1] == 0x00: + return "" + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + + def cmd_pso_longdata(self, p1, p2, data): + cmd_data0 = iso7816_compose(0x2a, p1, p2, data[:128], 0x10) + cmd_data1 = iso7816_compose(0x2a, p1, p2, data[128:]) + sw = self.icc_send_cmd(cmd_data0) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + sw = self.icc_send_cmd(cmd_data1) + if len(sw) != 2: + raise ValueError(sw) + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + + def cmd_internal_authenticate(self, data): + cmd_data = iso7816_compose(0x88, 0, 0, data) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if sw[0] == 0x90 and sw[1] == 0x00: + return "" + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + + def cmd_genkey(self, keyno): + if keyno == 1: + data = '\xb6\x00' + elif keyno == 2: + data = '\xb8\x00' + else: + data = '\xa4\x00' + cmd_data = iso7816_compose(0x47, 0x80, 0, data) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if sw[0] == 0x90 and sw[1] == 0x00: + return "" + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + pk = self.cmd_get_response(sw[1]) + return (pk[9:9+256], pk[9+256+2:9+256+2+3]) + + def cmd_get_public_key(self, keyno): + if keyno == 1: + data = '\xb6\x00' + elif keyno == 2: + data = '\xb8\x00' + else: + data = '\xa4\x00' + cmd_data = iso7816_compose(0x47, 0x81, 0, data) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + pk = self.cmd_get_response(sw[1]) + return (pk[9:9+256], pk[9+256+2:9+256+2+3]) + + def cmd_put_data_remove(self, tagh, tagl): + cmd_data = iso7816_compose(0xda, tagh, tagl, "") + sw = self.icc_send_cmd(cmd_data) + if sw[0] != 0x90 and sw[1] != 0x00: + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + + def cmd_put_data_key_import_remove(self, keyno): + if keyno == 1: + keyspec = "\xb6\x00" # SIG + elif keyno == 2: + keyspec = "\xb8\x00" # DEC + else: + keyspec = "\xa4\x00" # AUT + cmd_data = iso7816_compose(0xdb, 0x3f, 0xff, "\x4d\x02" + keyspec) + sw = self.icc_send_cmd(cmd_data) + if sw[0] != 0x90 and sw[1] != 0x00: + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + + def cmd_get_challenge(self): + cmd_data = iso7816_compose(0x84, 0x00, 0x00, '') + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + + def cmd_external_authenticate(self, keyno, signed): + cmd_data = iso7816_compose(0x82, 0x00, keyno, signed[0:128], cls=0x10) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + cmd_data = iso7816_compose(0x82, 0x00, keyno, signed[128:]) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError(sw) + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError("%02x%02x" % (sw[0], sw[1])) + + +class regnual(object): + def __init__(self, dev): + conf = dev.configurations[0] + intf_alt = conf.interfaces[0] + intf = intf_alt[0] + if intf.interfaceClass != 0xff: + raise ValueError("Wrong interface class") + self.__devhandle = dev.open() + try: + self.__devhandle.setConfiguration(conf) + except: + pass + self.__devhandle.claimInterface(intf) + self.__devhandle.setAltInterface(intf) + + def mem_info(self): + mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, + value = 0, index = 0, buffer = 8, + timeout = 10000) + start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0] + end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4] + return (start, end) + + def download(self, start, data): + addr = start + addr_end = (start + len(data)) & 0xffffff00 + i = (addr - 0x08000000) / 0x100 + j = 0 + print "start %08x" % addr + print "end %08x" % addr_end + while addr < addr_end: + print "# %08x: %d: %d : %d" % (addr, i, j, 256) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = 0, index = 0, + buffer = data[j*256:j*256+256], + timeout = 10000) + crc32code = crc32(data[j*256:j*256+256]) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if (crc32code ^ r_value) != 0xffffffff: + print "failure" + self.__devhandle.controlMsg(requestType = 0x40, request = 3, + value = i, index = 0, + buffer = None, + timeout = 10000) + time.sleep(0.010) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "failure" + i = i+1 + j = j+1 + addr = addr + 256 + residue = len(data) % 256 + if residue != 0: + print "# %08x: %d : %d" % (addr, i, residue) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = 0, index = 0, + buffer = data[j*256:], + timeout = 10000) + crc32code = crc32(data[j*256:].ljust(256,chr(255))) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if (crc32code ^ r_value) != 0xffffffff: + print "failure" + self.__devhandle.controlMsg(requestType = 0x40, request = 3, + value = i, index = 0, + buffer = None, + timeout = 10000) + time.sleep(0.010) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "failure" + + def protect(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 4, + value = 0, index = 0, buffer = None, + timeout = 10000) + time.sleep(0.100) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "protection failure" + + def finish(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 5, + value = 0, index = 0, buffer = None, + timeout = 10000) + + def reset_device(self): + try: + self.__devhandle.reset() + except: + pass + +def compare(data_original, data_in_device): + if data_original == data_in_device: + return True + raise ValueError("verify failed") + +def gnuk_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + for config in dev.configurations: + for intf in config.interfaces: + for alt in intf: + if alt.interfaceClass == CCID_CLASS and \ + alt.interfaceSubClass == CCID_SUBCLASS and \ + alt.interfaceProtocol == CCID_PROTOCOL_0: + yield dev, config, alt + +USB_VENDOR_FSIJ=0x234b +USB_PRODUCT_GNUK=0x0000 + +def gnuk_devices_by_vidpid(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + if dev.idVendor != USB_VENDOR_FSIJ: + continue + if dev.idProduct != USB_PRODUCT_GNUK: + continue + yield dev + +def get_gnuk_device(): + icc = None + for (dev, config, intf) in gnuk_devices(): + try: + icc = gnuk_token(dev, config, intf) + print "Device: ", dev.filename + print "Configuration: ", config.value + print "Interface: ", intf.interfaceNumber + break + except: + pass + if not icc: + raise ValueError("No ICC present") + status = icc.icc_get_status() + if status == 0: + pass # It's ON already + elif status == 1: + icc.icc_power_on() + else: + raise ValueError("Unknown ICC status", status) + return icc + +SHA256_OID_PREFIX="3031300d060960864801650304020105000420" + +def UNSIGNED(n): + return n & 0xffffffff + +def crc32(bytestr): + crc = binascii.crc32(bytestr) + return UNSIGNED(crc) diff --git a/tool/gnuk_upgrade.py b/tool/gnuk_upgrade.py new file mode 100755 index 0000000..ea63177 --- /dev/null +++ b/tool/gnuk_upgrade.py @@ -0,0 +1,507 @@ +#! /usr/bin/python + +""" +gnuk_upgrade.py - a tool to upgrade firmware of Gnuk Token + +Copyright (C) 2012 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 . +""" + +from struct import * +import sys, time, os, binascii, string + +# INPUT: binary files (regnual_image, upgrade_firmware_image) + +# Assume only single CCID device is attached to computer, and it's Gnuk Token + +import usb + +# USB class, subclass, protocol +CCID_CLASS = 0x0B +CCID_SUBCLASS = 0x00 +CCID_PROTOCOL_0 = 0x00 + +def icc_compose(msg_type, data_len, slot, seq, param, data): + return pack('BBBB', cls, ins, p1, p2) + else: + return pack('>BBBBB', cls, ins, p1, p2, data_len) + data + +class regnual(object): + def __init__(self, dev): + conf = dev.configurations[0] + intf_alt = conf.interfaces[0] + intf = intf_alt[0] + if intf.interfaceClass != 0xff: + raise ValueError, "Wrong interface class" + self.__devhandle = dev.open() + try: + self.__devhandle.setConfiguration(conf) + except: + pass + self.__devhandle.claimInterface(intf) + self.__devhandle.setAltInterface(intf) + + def mem_info(self): + mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, + value = 0, index = 0, buffer = 8, + timeout = 10000) + start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0] + end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4] + return (start, end) + + def download(self, start, data): + addr = start + addr_end = (start + len(data)) & 0xffffff00 + i = (addr - 0x08000000) / 0x100 + j = 0 + print "start %08x" % addr + print "end %08x" % addr_end + while addr < addr_end: + print "# %08x: %d: %d : %d" % (addr, i, j, 256) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = 0, index = 0, + buffer = data[j*256:j*256+256], + timeout = 10000) + crc32code = crc32(data[j*256:j*256+256]) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if (crc32code ^ r_value) != 0xffffffff: + print "failure" + self.__devhandle.controlMsg(requestType = 0x40, request = 3, + value = i, index = 0, + buffer = None, + timeout = 10000) + time.sleep(0.010) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "failure" + i = i+1 + j = j+1 + addr = addr + 256 + residue = len(data) % 256 + if residue != 0: + print "# %08x: %d : %d" % (addr, i, residue) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = 0, index = 0, + buffer = data[j*256:], + timeout = 10000) + crc32code = crc32(data[j*256:].ljust(256,chr(255))) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if (crc32code ^ r_value) != 0xffffffff: + print "failure" + self.__devhandle.controlMsg(requestType = 0x40, request = 3, + value = i, index = 0, + buffer = None, + timeout = 10000) + time.sleep(0.010) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "failure" + + def protect(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 4, + value = 0, index = 0, buffer = None, + timeout = 10000) + time.sleep(0.100) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "protection failure" + + def finish(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 5, + value = 0, index = 0, buffer = None, + timeout = 10000) + + def reset_device(self): + try: + self.__devhandle.reset() + except: + pass + +# This class only supports Gnuk (for now) +class gnuk_token(object): + def __init__(self, device, configuration, interface): + """ + __init__(device, configuration, interface) -> None + Initialize the device. + device: usb.Device object. + configuration: configuration number. + interface: usb.Interface object representing the interface and altenate setting. + """ + if interface.interfaceClass != CCID_CLASS: + raise ValueError, "Wrong interface class" + if interface.interfaceSubClass != CCID_SUBCLASS: + raise ValueError, "Wrong interface sub class" + self.__devhandle = device.open() + try: + self.__devhandle.setConfiguration(configuration) + except: + pass + self.__devhandle.claimInterface(interface) + self.__devhandle.setAltInterface(interface) + + self.__intf = interface.interfaceNumber + self.__alt = interface.alternateSetting + self.__conf = configuration + + self.__bulkout = 1 + self.__bulkin = 0x81 + + self.__timeout = 10000 + self.__seq = 0 + + def reset_device(self): + try: + self.__devhandle.reset() + except: + pass + + def stop_gnuk(self): + self.__devhandle.releaseInterface() + self.__devhandle.setConfiguration(0) + return + + def mem_info(self): + mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, + value = 0, index = 0, buffer = 8, + timeout = 10) + start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0] + end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4] + return (start, end) + + def download(self, start, data): + addr = start + addr_end = (start + len(data)) & 0xffffff00 + i = (addr - 0x20000000) / 0x100 + j = 0 + print "start %08x" % addr + print "end %08x" % addr_end + while addr < addr_end: + print "# %08x: %d : %d" % (addr, i, 256) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = i, index = 0, + buffer = data[j*256:j*256+256], + timeout = 10) + i = i+1 + j = j+1 + addr = addr + 256 + residue = len(data) % 256 + if residue != 0: + print "# %08x: %d : %d" % (addr, i, residue) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = i, index = 0, + buffer = data[j*256:], + timeout = 10) + + def execute(self, last_addr): + i = (last_addr - 0x20000000) / 0x100 + o = (last_addr - 0x20000000) % 0x100 + self.__devhandle.controlMsg(requestType = 0x40, request = 2, + value = i, index = o, buffer = None, + timeout = 10) + + def icc_get_result(self): + msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout) + if len(msg) < 10: + raise ValueError, "icc_get_result" + msg_type = msg[0] + data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24) + slot = msg[5] + seq = msg[6] + status = msg[7] + error = msg[8] + chain = msg[9] + data = msg[10:] + # XXX: check msg_type, data_len, slot, seq, error + return (status, chain, data) + + def icc_get_status(self): + msg = icc_compose(0x65, 0, 0, self.__seq, 0, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.__seq += 1 + status, chain, data = self.icc_get_result() + # XXX: check chain, data + return status + + def icc_power_on(self): + msg = icc_compose(0x62, 0, 0, self.__seq, 0, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.__seq += 1 + status, chain, data = self.icc_get_result() + # XXX: check status, chain + return data # ATR + + def icc_power_off(self): + msg = icc_compose(0x63, 0, 0, self.__seq, 0, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.__seq += 1 + status, chain, data = self.icc_get_result() + # XXX: check chain, data + return status + + def icc_send_data_block(self, data): + msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data) + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.__seq += 1 + return self.icc_get_result() + + def icc_send_cmd(self, data): + status, chain, data_rcv = self.icc_send_data_block(data) + if chain == 0: + return data_rcv + elif chain == 1: + d = data_rcv + while True: + msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "") + self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout) + self.__seq += 1 + status, chain, data_rcv = self.icc_get_result() + # XXX: check status + d += data_rcv + if chain == 2: + break + elif chain == 3: + continue + else: + raise ValueError, "icc_send_cmd chain" + return d + else: + raise ValueError, "icc_send_cmd" + + def cmd_get_response(self, expected_len): + cmd_data = iso7816_compose(0xc0, 0x00, 0x00, '') + pack('>B', expected_len) + response = self.icc_send_cmd(cmd_data) + return response[:-2] + + def cmd_verify(self, who, passwd): + cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError, sw + + def cmd_select_openpgp(self): + cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01") + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + + def cmd_external_authenticate(self, signed): + cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed[0:128], cls=0x10) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed[128:]) + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if not (sw[0] == 0x90 and sw[1] == 0x00): + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + + def cmd_get_challenge(self): + cmd_data = iso7816_compose(0x84, 0x00, 0x00, '') + sw = self.icc_send_cmd(cmd_data) + if len(sw) != 2: + raise ValueError, sw + if sw[0] != 0x61: + raise ValueError, ("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) + +def compare(data_original, data_in_device): + i = 0 + for d in data_original: + if ord(d) != data_in_device[i]: + raise ValueError, "verify failed at %08x" % i + i += 1 + +def ccid_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + for config in dev.configurations: + for intf in config.interfaces: + for alt in intf: + if alt.interfaceClass == CCID_CLASS and \ + alt.interfaceSubClass == CCID_SUBCLASS and \ + alt.interfaceProtocol == CCID_PROTOCOL_0: + yield dev, config, alt + +USB_VENDOR_FSIJ=0x234b +USB_PRODUCT_GNUK=0x0000 + +def gnuk_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + if dev.idVendor != USB_VENDOR_FSIJ: + continue + if dev.idProduct != USB_PRODUCT_GNUK: + continue + yield dev + +def to_string(t): + result = "" + for c in t: + result += chr(c) + return result + +from subprocess import check_output + +SHA256_OID_PREFIX="3031300d060960864801650304020105000420" + +# When user specify KEYGRIP, use it. Or else, connect to SCD directly. +def gpg_sign(keygrip, hash): + if keygrip: + result = check_output(["gpg-connect-agent", + "SIGKEY %s" % keygrip, + "SETHASH --hash=sha256 %s" % hash, + "PKSIGN --hash=sha256", "/bye"]) + else: + result = check_output(["gpg-connect-agent", + "SCD SETDATA " + SHA256_OID_PREFIX + hash, + "SCD PKAUTH OPENPGP.3", + "/bye"]) + signed = "" + while True: + i = result.find('%') + if i < 0: + signed += result + break + hex_str = result[i+1:i+3] + signed += result[0:i] + signed += chr(int(hex_str,16)) + result = result[i+3:] + + if keygrip: + pos = signed.index("D (7:sig-val(3:rsa(1:s256:") + 26 + signed = signed[pos:-7] + else: + pos = signed.index("D ") + 2 + signed = signed[pos:-4] # \nOK\n + if len(signed) != 256: + raise ValueError, binascii.hexlify(signed) + return signed + +def UNSIGNED(n): + return n & 0xffffffff + +def crc32(bytestr): + crc = binascii.crc32(bytestr) + return UNSIGNED(crc) + +def main(keygrip, data_regnual, data_upgrade): + l = len(data_regnual) + if (l & 0x03) != 0: + data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0)) + crc32code = crc32(data_regnual) + print "CRC32: %04x\n" % crc32code + data_regnual += pack('= 0: + self.buf_remained = chunk[pos+1:] + line = line + chunk[0:pos] + return line + else: + line = line + chunk + chunk = self.sock.recv(BUFLEN) + + def get_response(self): + r = self.response + result = "" + while True: + i = r.find('%') + if i < 0: + result += r + break + hex_str = r[i+1:i+3] + result += r[0:i] + result += chr(int(hex_str,16)) + r = r[i+3:] + return result + + def send_command(self, cmd): + self.sock.send(cmd) + self.response = "" + while True: + while True: + l = self.read_line() + if l[0] != '#': + break + if l[0] == 'D': + self.response += l[2:] + elif l[0] == 'O' and l[1] == 'K': + return True + elif l[0] == 'E' and l[1] == 'R' and l[2] == 'R': + return False + else: # XXX: S, INQUIRE, END + return False + + def close(self): + self.sock.send('BYE\n') + bye = self.read_line() + self.sock.close() + return bye # "OK closing connection" + +# Test +if __name__ == '__main__': + g = gpg_agent() + print g.read_line() + print g.send_command("KEYINFO --list --data\n") + kl_str = g.get_response() + kl_str = kl_str[0:-1] + kl = kl_str.split('\n') + import re + kl_o3 = [kg for kg in kl if re.search("OPENPGP\\.3", kg)] + print kl_o3 + kg = kl_o3[0].split(' ')[0] + print g.send_command("READKEY %s\n" % kg) + r = g.get_response() + import binascii + print binascii.hexlify(r) + print g.close() diff --git a/tool/hub_ctrl.py b/tool/hub_ctrl.py index 721b7d1..684b3bd 100755 --- a/tool/hub_ctrl.py +++ b/tool/hub_ctrl.py @@ -167,7 +167,7 @@ if __name__ == '__main__': option = sys.argv[1] sys.argv.pop(1) if option == '-h': - if bunum != None or devnum != None: + if busnum != None or devnum != None: exit_with_usage(sys.argv[0]) hub = int(sys.argv[1]) sys.argv.pop(1) diff --git a/tool/intel_hex.py b/tool/intel_hex.py index a2b0e28..a31a123 100644 --- a/tool/intel_hex.py +++ b/tool/intel_hex.py @@ -9,7 +9,7 @@ You can use/distribute/modify/etc. this for any purpose. import binascii -class intel_hex: +class intel_hex(object): def __init__(self, filename): self.start_address = 0 self.address = 0 diff --git a/tool/openocd-script/lock.tcl b/tool/openocd-script/lock.tcl index ecb5a96..9142fd0 100644 --- a/tool/openocd-script/lock.tcl +++ b/tool/openocd-script/lock.tcl @@ -3,4 +3,4 @@ reset halt stm32x lock 0 reset -exit +shutdown diff --git a/tool/openocd-script/options_read.tcl b/tool/openocd-script/options_read.tcl index 7ea8c40..7c7658a 100644 --- a/tool/openocd-script/options_read.tcl +++ b/tool/openocd-script/options_read.tcl @@ -2,4 +2,4 @@ init reset halt stm32x options_read 0 -exit +shutdown diff --git a/tool/openocd-script/unlock.tcl b/tool/openocd-script/unlock.tcl index 2f14aeb..67883ed 100644 --- a/tool/openocd-script/unlock.tcl +++ b/tool/openocd-script/unlock.tcl @@ -3,4 +3,4 @@ reset halt stm32x unlock 0 reset -exit +shutdown diff --git a/tool/openocd-script/write.tcl b/tool/openocd-script/write.tcl index 50d4382..1ddf8cd 100644 --- a/tool/openocd-script/write.tcl +++ b/tool/openocd-script/write.tcl @@ -2,4 +2,4 @@ init reset halt flash write_image erase gnuk.elf -exit +shutdown diff --git a/tool/pageant_proxy_to_gpg.py b/tool/pageant_proxy_to_gpg.py new file mode 100644 index 0000000..23d2873 --- /dev/null +++ b/tool/pageant_proxy_to_gpg.py @@ -0,0 +1,183 @@ +import os, sys, re, hashlib, binascii +from struct import * +from gpg_agent import gpg_agent +from sexp import sexp + +# Assume it's only OPENPGP.3 key and it's 2048-bit + +def debug(string): + print "DEBUG: %s" % string + sys.stdout.flush() + +def get_keygrip_list(keyinfo_result): + kl_str = keyinfo_result[0:-1] # Chop last newline + kl = kl_str.split('\n') + # filter by "OPENPGP.3", and only keygrip + return [kg.split(' ')[0] for kg in kl if re.search("OPENPGP\\.3", kg)] + +# Connect GPG-Agent, and get list of KEYGRIPs. +g = gpg_agent() +g.read_line() # Greeting message + +g.send_command('KEYINFO --list --data\n') +keyinfo_result = g.get_response() +keygrip_list = get_keygrip_list(keyinfo_result) + +debug(keygrip_list) + +keylist = [] +# For each KEYGRIP, get its PUBLIC-KEY. +for kg in keygrip_list: + g.send_command('READKEY %s\n' % kg) + key = sexp(g.get_response()) + # [ "public-key" [ "rsa" [ "n" MODULUS ] [ "e" EXPONENT] ] ] + n = key[1][1][1] + e = key[1][2][1] + debug(binascii.hexlify(n)) + debug(binascii.hexlify(e)) + keylist.append([n, e, kg]) + +# FIXME: should handle all keys, not only a single key +# FIXME: should support different key size +n = keylist[0][0] +e = keylist[0][1] +keygrip = keylist[0][2] + +ssh_rsa_public_blob = "\x00\x00\x00\x07ssh-rsa" + \ + "\x00\x00\x00\x03" + e + "\x00\x00\x01\x01" + n + +ssh_key_comment = "key_on_gpg" # XXX: get login from card for comment? + +import win32con, win32api, win32gui, ctypes, ctypes.wintypes + + +# For WM_COPYDATA structure +class COPYDATA(ctypes.Structure): + _fields_ = [ ('dwData', ctypes.wintypes.LPARAM), + ('cbData', ctypes.wintypes.DWORD), + ('lpData', ctypes.c_void_p) ] + +P_COPYDATA = ctypes.POINTER(COPYDATA) + +class SSH_MSG_HEAD(ctypes.BigEndianStructure): + _pack_ = 1 + _fields_ = [ ('msg_len', ctypes.c_uint32), + ('msg_type', ctypes.c_byte) ] + +P_SSH_MSG_HEAD = ctypes.POINTER(SSH_MSG_HEAD) + +class SSH_MSG_ID_ANSWER_HEAD(ctypes.BigEndianStructure): + _pack_ = 1 + _fields_ = [ ('msg_len', ctypes.c_uint32), + ('msg_type', ctypes.c_byte), + ('keys', ctypes.c_uint32)] + +P_SSH_MSG_ID_ANSWER = ctypes.POINTER(SSH_MSG_ID_ANSWER_HEAD) + +class SSH_MSG_SIGN_RESPONSE_HEAD(ctypes.BigEndianStructure): + _pack_ = 1 + _fields_ = [ ('msg_len', ctypes.c_uint32), + ('msg_type', ctypes.c_byte), + ('sig_len', ctypes.c_uint32)] + +P_SSH_MSG_SIGN_RESPONSE = ctypes.POINTER(SSH_MSG_SIGN_RESPONSE_HEAD) + + +FILE_MAP_ALL_ACCESS=0x000F001F + +class windows_ipc_listener(object): + def __init__(self): + message_map = { win32con.WM_COPYDATA: self.OnCopyData } + wc = win32gui.WNDCLASS() + wc.lpfnWndProc = message_map + wc.lpszClassName = 'Pageant' + hinst = wc.hInstance = win32api.GetModuleHandle(None) + classAtom = win32gui.RegisterClass(wc) + self.hwnd = win32gui.CreateWindow ( + classAtom, + "Pageant", + 0, + 0, + 0, + win32con.CW_USEDEFAULT, + win32con.CW_USEDEFAULT, + 0, + 0, + hinst, + None + ) + debug("created: window=%08x" % self.hwnd) + + def OnCopyData(self, hwnd, msg, wparam, lparam): + debug("WM_COPYDATA message") + debug(" window=%08x" % hwnd) + debug(" msg =%08x" % msg) + debug(" wparam=%08x" % wparam) + pCDS = ctypes.cast(lparam, P_COPYDATA) + debug(" dwData=%08x" % (pCDS.contents.dwData & 0xffffffff)) + debug(" len=%d" % pCDS.contents.cbData) + mapname = ctypes.string_at(pCDS.contents.lpData) + debug(" mapname='%s'" % ctypes.string_at(pCDS.contents.lpData)) + hMapObject = ctypes.windll.kernel32.OpenFileMappingA(FILE_MAP_ALL_ACCESS, 0, mapname) + if hMapObject == 0: + debug("error on OpenFileMapping") + return 0 + pBuf = ctypes.windll.kernel32.MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, 0) + if pBuf == 0: + ctypes.windll.kernel32.CloseHandle(hMapObject) + debug("error on MapViewOfFile") + return 0 + pSshMsg = ctypes.cast(pBuf, P_SSH_MSG_HEAD) + debug(" ssh_msg_len: %d" % pSshMsg.contents.msg_len) + debug(" ssh_msg_type: %d" % pSshMsg.contents.msg_type) + if pSshMsg.contents.msg_type == 11: # SSH2_AGENT_REQUEST_IDENTITIES + blob_len = len(ssh_rsa_public_blob) + cmnt_len = len(ssh_key_comment) + pAns = ctypes.cast(pBuf, P_SSH_MSG_ID_ANSWER) + pAns.contents.msg_len = 1+4+4+blob_len+4+cmnt_len + pAns.contents.msg_type = 12 # SSH2_AGENT_IDENTITIES_ANSWER + pAns.contents.keys = 1 + ctypes.memmove(pBuf+4+1+4, pack('>I', blob_len), 4) + ctypes.memmove(pBuf+4+1+4+4, ssh_rsa_public_blob, blob_len) + ctypes.memmove(pBuf+4+1+4+4+blob_len, pack('>I', cmnt_len), 4) + ctypes.memmove(pBuf+4+1+4+4+blob_len+4, ssh_key_comment, cmnt_len) + + debug("answer is:") + debug(" ssh_msg_len: %d" % pSshMsg.contents.msg_len) + debug(" ssh_msg_type: %d" % pSshMsg.contents.msg_type) + elif pSshMsg.contents.msg_type == 13: # SSH2_AGENT_SIGN_REQUEST + req_blob_len = unpack(">I", ctypes.string_at(pBuf+5, 4))[0] + req_blob = ctypes.string_at(pBuf+5+4, req_blob_len) + req_data_len = unpack(">I", ctypes.string_at(pBuf+5+4+req_blob_len,4))[0] + req_data = ctypes.string_at(pBuf+5+4+req_blob_len+4,req_data_len) + debug(" blob_len=%d" % req_blob_len) + debug(" data_len=%d" % req_data_len) + hash = hashlib.sha1(req_data).hexdigest() + debug(" hash=%s" % hash) + g.send_command('SIGKEY %s\n' % keygrip) + g.send_command('SETHASH --hash=sha1 %s\n' % hash) + g.send_command('PKSIGN\n') + sig = sexp(g.get_response()) + # [ "sig-val" [ "rsa" [ "s" "xxx" ] ] ] + sig = sig[1][1][1] + sig = "\x00\x00\x00\x07" + "ssh-rsa" + "\x00\x00\x01\x00" + sig # FIXME: should support different key size + siglen = len(sig) + debug("sig_len=%d" % siglen) + debug("sig=%s" % binascii.hexlify(sig)) + pRes = ctypes.cast(pBuf, P_SSH_MSG_SIGN_RESPONSE) + pRes.contents.msg_len = 1+4+siglen + pRes.contents.msg_type = 14 # SSH2_AGENT_SIGN_RESPONSE + pRes.contents.sig_len = siglen + ctypes.memmove(pBuf+4+1+4, sig, siglen) + debug("answer is:") + debug(" ssh_msg_len: %d" % pSshMsg.contents.msg_len) + debug(" ssh_msg_type: %d" % pSshMsg.contents.msg_type) + else: + exit(0) + ctypes.windll.kernel32.UnmapViewOfFile(pBuf) + ctypes.windll.kernel32.CloseHandle(hMapObject) + debug(" ssh_msg: done") + return 1 + +l = windows_ipc_listener() +win32gui.PumpMessages() diff --git a/tool/pinpadtest.py b/tool/pinpadtest.py new file mode 100755 index 0000000..735c9f8 --- /dev/null +++ b/tool/pinpadtest.py @@ -0,0 +1,436 @@ +#! /usr/bin/python + +""" +pinpadtest.py - a tool to test variable length pin entry with pinpad + +Copyright (C) 2011, 2012 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 . +""" + +import sys + +# Assume only single CCID device is attached to computer with card + +from smartcard.CardType import AnyCardType +from smartcard.CardRequest import CardRequest +from smartcard.util import toHexString + +from getpass import getpass + +CM_IOCTL_GET_FEATURE_REQUEST = (0x42000000 + 3400) +CM_IOCTL_VENDOR_IFD_EXCHANGE = (0x42000000 + 1) +FEATURE_VERIFY_PIN_DIRECT = 0x06 +FEATURE_MODIFY_PIN_DIRECT = 0x07 + +BY_ADMIN = 3 +BY_USER = 1 +PIN_MIN_DEFAULT = 6 # min of OpenPGP card +PIN_MAX_DEFAULT = 15 # max of VASCO DIGIPASS 920 + +def s2l(s): + return [ ord(c) for c in s ] + +def confirm_pin_setting(single_step): + if single_step: + return 0x01 # bConfirmPIN: new PIN twice + else: + return 0x03 # bConfirmPIN: old PIN and new PIN twice + +class Card(object): + def __init__(self, add_a_byte, pinmin, pinmax, fixed): + cardtype = AnyCardType() + cardrequest = CardRequest(timeout=10, cardType=cardtype) + cardservice = cardrequest.waitforcard() + self.connection = cardservice.connection + self.verify_ioctl = -1 + self.modify_ioctl = -1 + self.another_byte = add_a_byte + self.pinmin = pinmin + self.pinmax = pinmax + self.fixed = fixed + + def get_features(self): + p = self.connection.control(CM_IOCTL_GET_FEATURE_REQUEST, []) + i = 0 + while i < len(p): + code = p[i] + l = p[i+1] + i = i + 2 + if l == 4: + ioctl = (p[i] << 24) | (p[i+1] << 16) | (p[i+2] << 8) | p[i+3] + i = i + l + else: + i = i + l + continue + if code == FEATURE_VERIFY_PIN_DIRECT: + self.verify_ioctl = ioctl + elif code == FEATURE_MODIFY_PIN_DIRECT: + self.modify_ioctl = ioctl + if self.verify_ioctl == -1: + raise ValueError, "Not supported" + + def cmd_select_openpgp(self): + apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ] + response, sw1, sw2 = self.connection.transmit(apdu) + if sw1 == 0x61: # More data + response, sw1, sw2 = self.connection.transmit([0x00, 0xc0, 0, 0, sw2]) + elif not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("cmd_select_openpgp %02x %02x" % (sw1, sw2)) + + def possibly_add_dummy_byte(self): + if self.another_byte: + return [ 0 ] + else: + return [] + + def cmd_vega_alpha_disable_empty_verify(self): + apdu = [ 0xB5, # -| + 0x01, # | Pre-command parameters + 0x00, # -| + 0x03, # retry counter value (fixed value) + 0x00 # enable 3s timeout + ] + data = self.connection.control(CM_IOCTL_VENDOR_IFD_EXCHANGE, apdu) + + def cmd_verify_pinpad(self, who): + apdu = [0x00, 0x20, 0x00, 0x80+who ] + pin_verify = [ 0x00, # bTimeOut + 0x00, # bTimeOut2 + 0x82, # bmFormatString: Byte, pos=0, left, ASCII. + self.fixed, # bmPINBlockString + 0x00, # bmPINLengthFormat + self.pinmax, # wPINMaxExtraDigit Low (PINmax) + self.pinmin, # wPINMaxExtraDigit High (PINmin) + 0x02, # bEntryValidationCondition + 0x01, # bNumberMessage + 0x00, # wLangId Low + 0x00, # wLangId High + 0x00, # bMsgIndex + 0x00, # bTeoPrologue[0] + 0x00, # bTeoPrologue[1] + ] + if self.fixed > 0: + apdu += [ self.fixed ] + apdu += [ 255 ] * self.fixed + else: + apdu += self.possibly_add_dummy_byte() + pin_verify += [ len(apdu) ] # bTeoPrologue[2] + pin_verify += [ len(apdu), 0, 0, 0 ] + apdu + data = self.connection.control(self.verify_ioctl,pin_verify) + sw1 = data[0] + sw2 = data[1] + if not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("cmd_verify_pinpad %02x %02x" % (sw1, sw2)) + + def send_modify_pinpad(self, apdu, single_step, command): + if self.modify_ioctl == -1: + raise ValueError, "Not supported" + pin_modify = [ 0x00, # bTimerOut + 0x00, # bTimerOut2 + 0x82, # bmFormatString: Byte, pos=0, left, ASCII. + self.fixed, # bmPINBlockString + 0x00, # bmPINLengthFormat + 0x00, # bInsertionOffsetOld + self.fixed, # bInsertionOffsetNew + self.pinmax, # wPINMaxExtraDigit Low (PINmax) + self.pinmin, # wPINMaxExtraDigit High (PINmin) + confirm_pin_setting(single_step), + 0x02, # bEntryValidationCondition + 0x03, # bNumberMessage + 0x00, # wLangId Low + 0x00, # wLangId High + 0x00, # bMsgIndex1 + 0x01, # bMsgIndex2 + 0x02, # bMsgIndex3 + 0x00, # bTeoPrologue[0] + 0x00, # bTeoPrologue[1] + ] + if self.fixed > 0: + apdu += [ 2*self.fixed ] + apdu += [ 255 ] * (2*self.fixed) + else: + apdu += self.possibly_add_dummy_byte() + pin_modify += [ len(apdu) ] # bTeoPrologue[2] + pin_modify += [ len(apdu), 0, 0, 0 ] + apdu + data = self.connection.control(self.modify_ioctl,pin_modify) + sw1 = data[0] + sw2 = data[1] + if not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("%s %02x %02x" % (command, sw1, sw2)) + + def cmd_reset_retry_counter(self, who, data): + if who == BY_ADMIN: + apdu = [0x00, 0x2c, 0x02, 0x81, len(data) ] + data # BY_ADMIN + else: + apdu = [0x00, 0x2c, 0x00, 0x81, len(data) ] + data # BY_USER with resetcode + response, sw1, sw2 = self.connection.transmit(apdu) + if not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("cmd_reset_retry_counter %02x %02x" % (sw1, sw2)) + + # Note: CCID specification doesn't permit this (only 0x20 and 0x24) + def cmd_reset_retry_counter_pinpad(self, who): + if who == BY_ADMIN: + apdu = [0x00, 0x2c, 0x02, 0x81] # BY_ADMIN + self.send_modify_pinpad(apdu, True, "cmd_reset_retry_counter_pinpad") + else: + apdu = [0x00, 0x2c, 0x00, 0x81] # BY_USER with resetcode + self.send_modify_pinpad(apdu, False, "cmd_reset_retry_counter_pinpad") + + def cmd_put_resetcode(self, data): + apdu = [0x00, 0xda, 0x00, 0xd3, len(data) ] + data # BY_ADMIN + response, sw1, sw2 = self.connection.transmit(apdu) + if not (sw1 == 0x90 and sw2 == 0x00): + raise ValueError, ("cmd_put_resetcode %02x %02x" % (sw1, sw2)) + + # Note: CCID specification doesn't permit this (only 0x20 and 0x24) + def cmd_put_resetcode_pinpad(self): + apdu = [0x00, 0xda, 0x00, 0xd3] + self.send_modify_pinpad(apdu, True, "cmd_put_resetcode_pinpad") + + def cmd_change_reference_data_pinpad(self, who, is_exchange): + if is_exchange: + apdu = [0x00, 0x24, 1, 0x80+who] + else: + apdu = [0x00, 0x24, 0x00, 0x80+who] + self.send_modify_pinpad(apdu, is_exchange, + "cmd_change_reference_data_pinpad") + +COVADIS_VEGA_ALPHA="COVADIS VEGA-ALPHA (000000F5) 00 00" +# We need to set ifdDriverOptions in /etc/libccid_Info.plist: +# +# ifdDriverOptions +# 0x0001 +# +# 1: DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED +# the CCID Exchange command is allowed. You can use it through +# SCardControl(hCard, IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE, ...) + +def main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed): + card = Card(add_a_byte, pinmin, pinmax, fixed) + card.connection.connect() + + ident = card.connection.getReader() + print "Reader/Token:", ident + print "ATR:", toHexString( card.connection.getATR() ) + + if ident == COVADIS_VEGA_ALPHA: + card.cmd_vega_alpha_disable_empty_verify() + + card.get_features() + + card.cmd_select_openpgp() + if method == "verify": + if who == BY_USER: + print "Please input User's PIN" + else: + print "Please input Admin's PIN" + card.cmd_verify_pinpad(who) + elif method == "change": + if change_by_two_steps: + if who == BY_USER: + print "Please input User's PIN" + else: + print "Please input Admin's PIN" + card.cmd_verify_pinpad(who) + if who == BY_USER: + print "Please input New User's PIN twice" + else: + print "Please input New Admin's PIN twice" + card.cmd_change_reference_data_pinpad(who, True) + else: + if who == BY_USER: + print "Please input User's PIN" + print "and New User's PIN twice" + else: + print "Please input Admin's PIN" + print "and New Admin's PIN twice" + card.cmd_change_reference_data_pinpad(who, False) + elif method == "unblock": + if change_by_two_steps: + # It means using keyboard for new PIN + if who == BY_USER: + resetcode=s2l(getpass("Please input reset code from keyboard: ")) + newpin=s2l(getpass("Please input New User's PIN from keyboard: ")) + card.cmd_reset_retry_counter(who,resetcode+newpin) + else: + print "Please input Admin's PIN" + card.cmd_verify_pinpad(BY_ADMIN) + newpin=s2l(getpass("Please input New User's PIN from keyboard: ")) + card.cmd_reset_retry_counter(who,newpin) + else: + if who == BY_USER: + print "Please input reset code" + print "and New User's PIN twice" + else: + print "Please input Admin's PIN" + card.cmd_verify_pinpad(BY_ADMIN) + print "Please input New User's PIN twice" + card.cmd_reset_retry_counter_pinpad(who) + elif method == "put": + if change_by_two_steps: + # It means using keyboard for new PIN + print "Please input Admin's PIN" + card.cmd_verify_pinpad(BY_ADMIN) + resetcode=s2l(getpass("Please input New Reset Code from keyboard: ")) + card.cmd_put_resetcode(resetcode) + else: + print "Please input Admin's PIN" + card.cmd_verify_pinpad(BY_ADMIN) + print "Please input New Reset Code twice" + card.cmd_put_resetcode_pinpad() + else: + raise ValueError, method + card.connection.disconnect() + + print "OK." + return 0 + +def print_usage(): + print "pinpad-test: testing pinentry of PC/SC card reader" + print " help:" + print "\t--help:\t\tthis message" + print " method:\t\t\t\t\t\t\t[verify]" + print "\t--verify:\tverify PIN" + print "\t--change:\tchange PIN (old PIN, new PIN twice)" + print "\t--change2:\tchange PIN by two steps (old PIN, new PIN twice)" + print "\t--unblock:\tunblock PIN (admin PIN/resetcode, new PIN twice)" + print "\t--unblock2:\tunblock PIN (admin PIN:pinpad, new PIN:kbd)" + print "\t--put:\t\tsetup resetcode (admin PIN, new PIN twice)" + print "\t--put2::\t\tsetup resetcode (admin PIN:pinpad, new PIN:kbd)" + print " options:" + print "\t--fixed N:\tUse fixed length input" + print "\t--admin:\tby administrator\t\t\t[False]" + print "\t--add:\t\tadd a dummy byte at the end of APDU\t[False]" + print "\t--pinmin:\tspecify minimum length of PIN\t\t[6]" + print "\t--pinmax:\tspecify maximum length of PIN\t\t[15]" + print "EXAMPLES:" + print " $ pinpad-test # verify user's PIN " + print " $ pinpad-test --admin # verify admin's PIN " + print " $ pinpad-test --change # change user's PIN " + print " $ pinpad-test --change --admin # change admin's PIN " + print " $ pinpad-test --change2 # change user's PIN by two steps" + print " $ pinpad-test --change2 --admin # change admin's PIN by two steps" + print " $ pinpad-test --unblock # change user's PIN by reset code" + print " $ pinpad-test --unblock --admin # change user's PIN by admin's PIN" + print " $ pinpad-test --put # setup resetcode " + +if __name__ == '__main__': + who = BY_USER + method = "verify" + add_a_byte = False + pinmin = PIN_MIN_DEFAULT + pinmax = PIN_MAX_DEFAULT + change_by_two_steps = False + fixed=0 + while len(sys.argv) >= 2: + option = sys.argv[1] + sys.argv.pop(1) + if option == '--admin': + who = BY_ADMIN + elif option == '--change': + method = "change" + elif option == '--change2': + method = "change" + change_by_two_steps = True + elif option == '--unblock': + method = "unblock" + elif option == '--unblock2': + method = "unblock" + change_by_two_steps = True + elif option == '--add': + add_a_byte = True + elif option == '--fixed': + fixed = int(sys.argv[1]) + sys.argv.pop(1) + elif option == '--pinmin': + pinmin = int(sys.argv[1]) + sys.argv.pop(1) + elif option == '--pinmax': + pinmax = int(sys.argv[1]) + sys.argv.pop(1) + elif option == '--put': + method = "put" + elif option == '--put2': + method = "put" + change_by_two_steps = True + elif option == "verify": + method = "verify" + elif option == '--help': + print_usage() + exit(0) + else: + raise ValueError, option + main(who, method, add_a_byte, pinmin, pinmax, change_by_two_steps, fixed) + +# Failure +# 67 00: Wrong length; no further indication +# 69 82: Security status not satisfied: pin doesn't match +# 69 85: Conditions of use not satisfied +# 6b 00: Wrong parameters P1-P2 +# 6b 80 +# 64 02: PIN different + +# General +# OpenPGP card v2 doesn't support CHANGE REFERENCE DATA in exchanging +# mode (with P1 == 01, replacing PIN). +# FAIL: --change2 fails with 6b 00 (after input of PIN) +# FAIL: --change2 --admin fails with 6b 00 (after input of PIN) + +# "FSIJ Gnuk (0.16-34006F06) 00 00" +# Works well except --change2 +# It could support --put and --unblock, but currently it's disabled. + +# "Vasco DIGIPASS 920 [CCID] 00 00" +# OK: --verify +# OK: --verify --admin +# OK: --change +# OK: --change --admin +# OK: --unblock +# FAIL: --unblock --admin fails with 69 85 (after input of PIN) +# FAIL: --put fails with 6b 80 (before input of resetcode) +# OK: --put2 +# FAIL: --unblock2 fails with 69 85 +# FAIL: --unblock2 --admin fails with 69 85 (after input of PIN) + +# 0c4b:0500 Reiner SCT Kartensysteme GmbH +# "REINER SCT cyberJack RFID standard (7592671050) 00 00" +# OK: --verify +# OK: --verify --admin +# OK: --change +# OK: --change --admin +# OK: --unblock +# OK: --unblock --admin +# FAIL: --put fails with 69 85 + +# Gemalto GemPC Pinpad 00 00 +# It asks users PIN with --add but it results 67 00 +# It seems that it doesn't support variable length PIN +# Firmware version: GemTwRC2-V2.10-GL04 + +# 072f:90d2 Advanced Card Systems, Ltd +# ACS ACR83U 01 00 +# --verify failed with 6b 80 + +# 08e6:34c2 Gemplus +# Gemalto Ezio Shield PinPad 01 00 +# works well +# FAIL: --unblock2 fails with 6d 00 + +# 076b:3821 OmniKey AG CardMan 3821 +# OmniKey CardMan 3821 01 00 +# Works well with --pinmax 31 --pinmin 1 diff --git a/tool/rsa.py b/tool/rsa.py new file mode 100644 index 0000000..00371f9 --- /dev/null +++ b/tool/rsa.py @@ -0,0 +1,70 @@ +from binascii import hexlify, unhexlify +import string +from os import urandom + +def read_key_from_file(file): + f = open(file) + n_str = f.readline()[:-1] + e_str = f.readline()[:-1] + p_str = f.readline()[:-1] + q_str = f.readline()[:-1] + f.close() + e = int(e_str, 16) + p = int(p_str, 16) + q = int(q_str, 16) + n = int(n_str, 16) + if n != p * q: + raise ValueError("wrong key", p, q, n) + return (unhexlify(n_str), unhexlify(e_str), unhexlify(p_str), unhexlify(q_str), e, p, q, n) + +# egcd and modinv are from wikibooks +# https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm + +def egcd(a, b): + if a == 0: + return (b, 0, 1) + else: + g, y, x = egcd(b % a, a) + return (g, x - (b // a) * y, y) + +def modinv(a, m): + g, x, y = egcd(a, m) + if g != 1: + raise Exception('modular inverse does not exist') + else: + return x % m + +def pkcs1_pad_for_sign(digestinfo): + byte_repr = '\x00' + '\x01' + string.ljust('', 256 - 19 - 32 - 3, '\xff') \ + + '\x00' + digestinfo + return int(hexlify(byte_repr), 16) + +def compute_signature(key, digestinfo): + e = key[4] + p = key[5] + q = key[6] + n = key[7] + p1 = p - 1 + q1 = q - 1 + h = p1 * q1 + d = modinv(e, h) + dp = d % p1 + dq = d % q1 + qp = modinv(q, p) + + input = pkcs1_pad_for_sign(digestinfo) + t1 = pow(input, dp, p) + t2 = pow(input, dq, q) + t = ((t1 - t2) * qp) % p + sig = t2 + t * q + return sig + +def integer_to_bytes_256(i): + s = hex(i)[2:] + s = s.rstrip('L') + if len(s) & 1: + s = '0' + s + return string.rjust(unhexlify(s), 256, '\x00') + +def get_raw_pubkey(key): + return key[0] diff --git a/tool/rsa_example.key b/tool/rsa_example.key new file mode 100644 index 0000000..cdf2d5e --- /dev/null +++ b/tool/rsa_example.key @@ -0,0 +1,4 @@ +9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9 +010001 +b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907 +dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf diff --git a/tool/sexp.py b/tool/sexp.py new file mode 100644 index 0000000..a705054 --- /dev/null +++ b/tool/sexp.py @@ -0,0 +1,65 @@ +# SEXP (S-expressions) Basic Transport Support +# +# See: http://people.csail.mit.edu/rivest/sexp.html +# + +import re + +WHITESPACE='[ \n\t\v\r\f]+' +re_ws = re.compile(WHITESPACE) +DIGITS='[0-9]+' +re_digit = re.compile(DIGITS) + +def skip_whitespace(string, pos): + m = re_ws.match(string, pos) + if m: + return m.start() + else: + return pos + +def sexp_match(string, ch, pos): + pos = skip_whitespace(string,pos) + if string[pos] == ch: + return pos+1 + else: + raise ValueError("expect '%s'" % ch) + +def sexp_parse_simple_string(string, pos): + pos = skip_whitespace(string,pos) + m = re_digit.match(string, pos) + if m: + length = int(string[m.start():m.end()],10) + pos = sexp_match(string, ':', m.end()) + return (string[pos:pos+length], pos+length) + else: + raise ValueError('expect digit') + +def sexp_parse_list(string,pos): + l = [] + while True: + pos = skip_whitespace(string,pos) + if string[pos] == ')': + return (l, pos) + else: + (sexp, pos) = sexp_parse(string,pos) + l.append(sexp) + +def sexp_parse(string, pos=0): + pos = skip_whitespace(string,pos) + if string[pos] == '(': + (l, pos) = sexp_parse_list(string,pos+1) + pos = sexp_match(string, ')', pos) + return (l, pos) + elif string[pos] == '[': + pos = skip_whitespace(string,pos) + (dsp, pos) = sexp_parse_simple_string(string,pos+1) + pos = sexp_match(string, ']', pos) + pos = skip_whitespace(string,pos) + (ss, pos) = sexp_parse_simple_string(string, pos) + return ((dsp, ss), pos) + else: + return sexp_parse_simple_string(string, pos) + +def sexp(string): + (sexp, pos) = sexp_parse(string) + return sexp diff --git a/tool/stlinkv2.py b/tool/stlinkv2.py new file mode 100755 index 0000000..8a2023f --- /dev/null +++ b/tool/stlinkv2.py @@ -0,0 +1,688 @@ +#! /usr/bin/python + +""" +stlinkv2.py - a tool to control ST-Link/V2 + +Copyright (C) 2012 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 . +""" + +from struct import * +import sys, time +import usb +from colorama import init as colorama_init, Fore, Back, Style + +# INPUT: binary file + +# Assumes only single ST-Link/V2 device is attached to computer. + + +GPIOA=0x40010800 +GPIOB=0x40010C00 +OPTION_BYTES_ADDR=0x1ffff800 +RDP_KEY=0x00a5 # Unlock readprotection +FLASH_BASE_ADDR=0x40022000 + +FLASH_KEYR= FLASH_BASE_ADDR+0x04 +FLASH_OPTKEYR= FLASH_BASE_ADDR+0x08 +FLASH_SR= FLASH_BASE_ADDR+0x0c +FLASH_CR= FLASH_BASE_ADDR+0x10 +FLASH_AR= FLASH_BASE_ADDR+0x14 +FLASH_OBR= FLASH_BASE_ADDR+0x1c + +FLASH_KEY1=0x45670123 +FLASH_KEY2=0xcdef89ab + +FLASH_SR_BSY= 0x0001 +FLASH_SR_PGERR= 0x0004 +FLASH_SR_WRPRTERR= 0x0010 +FLASH_SR_EOP= 0x0020 + +FLASH_CR_PG= 0x0001 +FLASH_CR_PER= 0x0002 +FLASH_CR_MER= 0x0004 +FLASH_CR_OPTPG= 0x0010 +FLASH_CR_OPTER= 0x0020 +FLASH_CR_STRT= 0x0040 +FLASH_CR_LOCK= 0x0080 +FLASH_CR_OPTWRE= 0x0200 + + +SPI1= 0x40013000 + +def uint32(v): + return v[0] + (v[1]<<8) + (v[2]<<16) + (v[3]<<24) + +## HERE comes: "movw r2,#SIZE" instruction +prog_flash_write_body = "\x0A\x48" + "\x0B\x49" + \ + "\x08\x4C" + "\x01\x25" + "\x14\x26" + "\x00\x27" + "\x25\x61" + \ + "\xC3\x5B" + "\xCB\x53" + "\xE3\x68" + "\x2B\x42" + "\xFC\xD1" + \ + "\x33\x42" + "\x02\xD1" + "\x02\x37" + "\x97\x42" + "\xF5\xD1" + \ + "\x00\x27" + "\x27\x61" + "\x00\xBE" + "\x00\x20\x02\x40" + \ + "\x38\x00\x00\x20" +# .SRC_ADDR: 0x20000038 +## HERE comes: target_addr in 4-byte +# .TARGET_ADDR + +def gen_prog_flash_write(addr,size): + return pack(">12), (0xf2 | (size&0x0800)>>9), + (size & 0x00ff), (0x02 | ((size&0x0700) >> 4))) + \ + prog_flash_write_body + pack(">12), (0xf2 | (val&0x0800)>>9), + (val & 0x00ff), (0x00 | ((val&0x0700) >> 4))) + \ + prog_option_bytes_write_body + pack("APB2ENR + self.write_memory_u32(0x4002100c, 4|8|0x1000) # RCC->APB2RSTR + self.write_memory_u32(0x4002100c, 0) + self.write_memory_u32(GPIOA+0x0c, 0xffffffff) # ODR + self.write_memory_u32(GPIOA+0x04, 0x88888383) # CRH + self.write_memory_u32(GPIOA+0x00, 0xBBB38888) # CRL + self.write_memory_u32(GPIOB+0x0c, 0xffffffff) # ODR + self.write_memory_u32(GPIOB+0x04, 0x88888888) # CRH + self.write_memory_u32(GPIOB+0x00, 0x88888883) # CRL + + # For FST-01-00 and FST-01: LED on, USB disconnect + def usb_disconnect(self): + self.write_memory_u32(GPIOA+0x0c, 0xfffffbff) # ODR + + # For FST-01-00 and FST-01: LED off, USB connect + def finish_gpio(self): + self.write_memory_u32(GPIOA+0x0c, 0xfffffeff) # ODR + self.write_memory_u32(GPIOB+0x0c, 0xfffffffe) # ODR + apb2enr = self.read_memory_u32(0x40021018) + apb2enr = apb2enr & ~(4 | 8 | 0x1000) + self.write_memory_u32(0x40021018, apb2enr) # RCC->APB2ENR + + def spi_flash_init(self): + self.write_memory_u32(SPI1+0x00, 0x0004); # CR1 <= MSTR + i2scfgr = self.read_memory_u32(SPI1+0x1c) # I2SCFGR + i2scfgr = i2scfgr & 0xf7ff # + self.write_memory_u32(SPI1+0x1c, i2scfgr); # I2SCFGR <= SPI mode + self.write_memory_u32(SPI1+0x10, 7); # CRCPR <= 7 + self.write_memory_u32(SPI1+0x04, 0x04); # CR2 <= SSOE + self.write_memory_u32(SPI1+0x00, 0x0044); # CR1 <= MSTR | SPE + + def spi_flash_select(self, enable): + if enable: + self.write_memory_u32(GPIOA+0x0c, 0xffffffef) # ODR + else: + self.write_memory_u32(GPIOA+0x0c, 0xffffffff) # ODR + + def spi_flash_sendbyte(self, v): + i = 0 + while True: + status = self.read_memory_u32(SPI1+0x08) # SR + if status & 0x02 != 0: # TXE (Data Empty) + break + time.sleep(0.01) + i = i + 1 + if i > 10: + raise TimeOutError('spi_flash_sendbyte') + self.write_memory_u32(SPI1+0x0c, v) # DR + i = 0 + while True: + status = self.read_memory_u32(SPI1+0x08) # SR + if status & 0x01 != 0: # RXNE (Data Not Empty) + break + time.sleep(0.01) + i = i + 1 + if i > 10: + raise TimeOutError('spi_flash_sendbyte') + v = self.read_memory_u32(SPI1+0x0c) # DR + return v + + def spi_flash_read_id(self): + self.spi_flash_select(True) + self.spi_flash_sendbyte(0x9f) + t0 = self.spi_flash_sendbyte(0xa5) + t1 = self.spi_flash_sendbyte(0xa5) + t2 = self.spi_flash_sendbyte(0xa5) + self.spi_flash_select(False) + return (t0 << 16) | (t1 << 8) | t2 + + def protection(self): + return (self.read_memory_u32(FLASH_OBR) & 0x0002) != 0 + + def blank_check(self): + prog = gen_prog_blank_check(0x20000) # 128KiB XXX: table lookup??? + self.write_memory(SRAM_ADDRESS, prog) + self.write_reg(15, SRAM_ADDRESS) + self.run() + i = 0 + while self.get_status() == 0x80: + time.sleep(0.050) + i = i + 1 + if i >= 10: + raise TimeOutError("blank check") + + r0_value = self.read_reg(0) + return r0_value == 0 + + def option_bytes_read(self): + return self.read_memory_u32(OPTION_BYTES_ADDR) + + def option_bytes_write(self,addr,val): + self.write_memory_u32(FLASH_KEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_KEYR, FLASH_KEY2) + self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR) + + self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY2) + + prog = gen_prog_option_bytes_write(addr,val) + self.write_memory(SRAM_ADDRESS, prog) + self.write_reg(15, SRAM_ADDRESS) + self.run() + i = 0 + while self.get_status() == 0x80: + time.sleep(0.050) + i = i + 1 + if i >= 10: + raise TimeOutError("option bytes write") + + status = self.read_memory_u32(FLASH_SR) + self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK) + if (status & FLASH_SR_EOP) == 0: + raise OperationFailure("option bytes write") + + def option_bytes_erase(self): + self.write_memory_u32(FLASH_KEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_KEYR, FLASH_KEY2) + self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR) + + self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_OPTKEYR, FLASH_KEY2) + + self.write_memory_u32(FLASH_CR, FLASH_CR_OPTER) + self.write_memory_u32(FLASH_CR, FLASH_CR_STRT | FLASH_CR_OPTER) + + i = 0 + while True: + status = self.read_memory_u32(FLASH_SR) + if (status & FLASH_SR_BSY) == 0: + break + i = i + 1 + if i >= 1000: + break + + self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK) + if (status & FLASH_SR_EOP) == 0: + raise OperationFailure("option bytes erase") + + def flash_write_internal(self, addr, data, off, size): + prog = gen_prog_flash_write(addr,size) + self.write_memory(SRAM_ADDRESS, prog+data[off:off+size]) + self.write_reg(15, SRAM_ADDRESS) + self.run() + i = 0 + while self.get_status() == 0x80: + time.sleep(0.050) + i = i + 1 + if i >= BLOCK_WRITE_TIMEOUT: + raise TimeOutError("flash write") + status = self.read_memory_u32(FLASH_SR) + if (status & FLASH_SR_PGERR) != 0: + raise OperationFailure("flash write: write to not erased part") + if (status & FLASH_SR_WRPRTERR) != 0: + raise OperationFailure("flash write: write to protected part") + + def flash_write(self, addr, data): + self.write_memory_u32(FLASH_KEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_KEYR, FLASH_KEY2) + self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR) + + off = 0 + while True: + if len(data[off:]) > BLOCK_SIZE: + size = BLOCK_SIZE + self.flash_write_internal(addr, data, off, size) + off = off + size + addr = addr + size + else: + size = len(data[off:]) + self.flash_write_internal(addr, data, off, size) + break + + self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK) + + def flash_erase_all(self): + self.write_memory_u32(FLASH_KEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_KEYR, FLASH_KEY2) + self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR) + + self.write_memory_u32(FLASH_CR, FLASH_CR_MER) + self.write_memory_u32(FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER) + + i = 0 + while True: + status = self.read_memory_u32(FLASH_SR) + if (status & FLASH_SR_BSY) == 0: + break + i = i + 1 + time.sleep(0.050) + if i >= 100: + break + + self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK) + + if (status & FLASH_SR_EOP) == 0: + raise OperationFailure("flash erase all") + + def flash_erase_page(self, addr): + self.write_memory_u32(FLASH_KEYR, FLASH_KEY1) + self.write_memory_u32(FLASH_KEYR, FLASH_KEY2) + + self.write_memory_u32(FLASH_SR, FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR) + + self.write_memory_u32(FLASH_CR, FLASH_CR_PER) + self.write_memory_u32(FLASH_AR, addr) + self.write_memory_u32(FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER) + + i = 0 + while True: + status = self.read_memory_u32(FLASH_SR) + if (status & FLASH_SR_BSY) == 0: + break + i = i + 1 + if i >= 1000: + break + + self.write_memory_u32(FLASH_CR, FLASH_CR_LOCK) + + if (status & FLASH_SR_EOP) == 0: + raise OperationFailure("flash page erase") + + def start(self): + mode = self.stl_mode() + if mode == 2: + return + elif mode != 1: + self.exit_from_dfu() + mode = self.stl_mode() + print "Change ST-Link/V2 mode to: %04x" % mode + self.enter_swd() + s = self.get_status() + if s != 0x0080: + raise ValueError("Status of core is not running.", s) + mode = self.stl_mode() + if mode != 2: + raise ValueError("Failed to switch debug mode.", mode) + + +USB_VENDOR_ST=0x0483 # 0x0483 SGS Thomson Microelectronics +USB_VENDOR_STLINKV2=0x3748 # 0x3748 ST-LINK/V2 + +def stlinkv2_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + if dev.idVendor != USB_VENDOR_ST: + continue + if dev.idProduct != USB_VENDOR_STLINKV2: + continue + yield dev + +def compare(data_original, data_in_device): + i = 0 + for d in data_original: + if ord(d) != data_in_device[i]: + raise ValueError("Verify failed at:", i) + i += 1 + +def open_stlinkv2(): + for d in stlinkv2_devices(): + try: + stl = stlinkv2(d) + return stl + except: + pass + return None + +def help(): + print "stlinkv2.py [-h]: Show this help message" + print "stlinkv2.py [-e]: Erase flash ROM" + print "stlinkv2.py [-u]: Unlock flash ROM" + print "stlinkv2.py [-s]: Show status" + print "stlinkv2.py [-b] [-n] [-r] [-i] FILE: Write content of FILE to flash ROM" + print " -b: Blank check before write (auto erase when not blank)" + print " -n: Don't enable read protection after write" + print " -r: Don't reset after write" + print " -i: Don't test SPI flash" + + +def main(show_help, erase_only, no_protect, spi_flash_check, + reset_after_successful_write, + skip_blank_check, status_only, unlock, data): + if show_help or len(sys.argv) != 1: + help() + return 1 + + stl = open_stlinkv2() + if not stl: + raise ValueError("No ST-Link/V2 device found.", None) + + stl.start() + core_id = stl.core_id() + chip_id = stl.read_memory_u32(0xE0042000) + + # FST-01 chip id: 0x20036410 + print "CORE: %08x, CHIP_ID: %08x" % (core_id, chip_id) + print "Flash ROM read protection:", + protection = stl.protection() + if protection: + print "ON" + else: + print "off" + + option_bytes = stl.option_bytes_read() + print "Option bytes: %08x" % option_bytes + if (option_bytes & 0xff) == RDP_KEY: + ob_protection_enable = False + else: + ob_protection_enable = True + + stl.enter_debug() + status = stl.get_status() + if status != 0x0081: + raise ValueError("Status of core is not halt.", status) + + if protection: + if status_only: + print "The MCU is now stopped." + return 0 + elif not unlock: + raise OperationFailure("Flash ROM is protected") + else: + if not skip_blank_check: + stl.reset_sys() + blank = stl.blank_check() + print "Flash ROM blank check: %s" % blank + else: + blank = True + if status_only: + stl.reset_sys() + stl.run() + stl.exit_debug() + return 0 + elif unlock and not ob_protection_enable: + print "No need to unlock. Protection is not enabled." + return 1 + + if erase_only: + if blank: + print "No need to erase" + return 0 + + stl.setup_gpio() + + if unlock: + if option_bytes != 0xff: + stl.reset_sys() + stl.option_bytes_erase() + stl.reset_sys() + stl.option_bytes_write(OPTION_BYTES_ADDR,RDP_KEY) + stl.usb_disconnect() + time.sleep(0.100) + stl.finish_gpio() + print "Flash ROM read protection disabled. Reset the board, now." + return 0 + + if spi_flash_check: + stl.spi_flash_init() + id = stl.spi_flash_read_id() + print "SPI Flash ROM ID: %06x" % id + if id != 0xbf254a: + raise ValueError("bad spi flash ROM ID") + + if not blank: + print "ERASE ALL" + stl.reset_sys() + stl.flash_erase_all() + + if erase_only: + stl.usb_disconnect() + time.sleep(0.100) + stl.finish_gpio() + return 0 + + time.sleep(0.100) + + print "WRITE" + stl.flash_write(0x08000000, data) + + print "VERIFY" + data_received = () + size = len(data) + off = 0 + while size > 0: + if size > 1024: + blk_size = 1024 + else: + blk_size = size + data_received = data_received + stl.read_memory(0x08000000+off, 1024) + size = size - blk_size + off = off + blk_size + compare(data, data_received) + + if not no_protect: + print "PROTECT" + stl.option_bytes_erase() + print "Flash ROM read protection enabled. Reset the board to enable protection." + + if reset_after_successful_write: + stl.usb_disconnect() + stl.reset_sys() + stl.run() + stl.exit_debug() + else: + stl.finish_gpio() + + stl.shutdown() + return 0 + +if __name__ == '__main__': + show_help = False + erase_only = False + no_protect = False + reset_after_successful_write = True + skip_blank_check=True + status_only = False + unlock = False + data = None + spi_flash_check = True + + while len(sys.argv) > 1: + if sys.argv[1] == '-h': + sys.argv.pop(1) + show_help = True + break + elif sys.argv[1] == '-e': + sys.argv.pop(1) + erase_only = True + skip_blank_check=False + break + elif sys.argv[1] == '-u': + sys.argv.pop(1) + unlock = True + break + elif sys.argv[1] == '-s': + sys.argv.pop(1) + status_only = True + skip_blank_check=False + break + elif sys.argv[1] == '-b': + skip_blank_check=False + elif sys.argv[1] == '-n': + no_protect = True + elif sys.argv[1] == '-r': + reset_after_successful_write = False + elif sys.argv[1] == '-i': + spi_flash_check = False + else: + filename = sys.argv[1] + f = open(filename,'rb') + data = f.read() + f.close() + sys.argv.pop(1) + + colorama_init() + + try: + r = main(show_help, erase_only, no_protect, spi_flash_check, + reset_after_successful_write, + skip_blank_check, status_only, unlock, data) + if r == 0: + print Fore.WHITE + Back.BLUE + Style.BRIGHT + "SUCCESS" + Style.RESET_ALL + sys.exit(r) + except Exception as e: + print Back.RED + Style.BRIGHT + repr(e) + Style.RESET_ALL diff --git a/tool/upgrade_by_passwd.py b/tool/upgrade_by_passwd.py new file mode 100755 index 0000000..4ef0f0f --- /dev/null +++ b/tool/upgrade_by_passwd.py @@ -0,0 +1,112 @@ +#! /usr/bin/python + +""" +upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token + which is just shipped from factory + +Copyright (C) 2012 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 . +""" + +from gnuk_token import * +import sys, binascii, time, os +import rsa + +DEFAULT_PW3 = "12345678" +BY_ADMIN = 3 + +KEYNO_FOR_AUTH=2 + +def main(passwd, data_regnual, data_upgrade): + l = len(data_regnual) + if (l & 0x03) != 0: + data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0)) + crc32code = crc32(data_regnual) + print "CRC32: %04x\n" % crc32code + data_regnual += pack(' 1 and sys.argv[1] == '-p': + from getpass import getpass + passwd = getpass("Admin password: ") + sys.argv.pop(1) + filename_regnual = sys.argv[1] + filename_upgrade = sys.argv[2] + f = open(filename_regnual) + data_regnual = f.read() + f.close() + print "%s: %d" % (filename_regnual, len(data_regnual)) + f = open(filename_upgrade) + data_upgrade = f.read() + f.close() + print "%s: %d" % (filename_upgrade, len(data_upgrade)) + # First 4096-byte in data_upgrade is SYS, so, skip it. + main(passwd, data_regnual, data_upgrade[4096:]) diff --git a/tool/usb_strings.py b/tool/usb_strings.py new file mode 100755 index 0000000..5d50c55 --- /dev/null +++ b/tool/usb_strings.py @@ -0,0 +1,60 @@ +#! /usr/bin/python + +""" +usb_strings.py - a tool to dump USB string + +Copyright (C) 2012 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 . +""" + +import usb, sys + +USB_VENDOR_FSIJ=0x234b +USB_PRODUCT_GNUK=0x0000 + +def gnuk_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + if dev.idVendor != USB_VENDOR_FSIJ: + continue + if dev.idProduct != USB_PRODUCT_GNUK: + continue + yield dev + +title = [ '', 'Vendor', 'Product', 'Serial', 'Revision', 'Config', 'Sys' ] + +def main(n): + for dev in gnuk_devices(): + handle = dev.open() + print "Device: ", dev.filename + try: + for i in range(1,n): + str = handle.getString(i, 512) + print "%10s: %s" % (title[i], str) + except: + pass + del dev + +if __name__ == '__main__': + if len(sys.argv) > 1: + n = int(sys.argv[1]) + else: + n = 7 # Gnuk has seven strings + main(n)