From 4fe93be7257bbdd49bb6d7adf77fad244f1ab073 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 2 Jul 2021 15:02:33 +0200 Subject: [PATCH] introduce support for new ngff_cardem board This adds support for the new ngff_cardem board, a board that basically combines a ngff breakout board with a built-in SIMtrace2. Cardem works, but depending on the modem it might need a adjusted ATR to ensure a lower baud rate is used by the modem, high rates might lead to weird power cycling of the card after a few transfers. Trace was also tested and appears to work as expected. Change-Id: Ia96124fbe8a752c98e7fd4096d542a3b2b9bc255 --- contrib/flash.py | 3 +- contrib/simtrace.lua | 1 + firmware/apps/cardem/main.c | 5 + firmware/libboard/ngff_cardem/include/board.h | 166 ++++++++++++++++++ .../libboard/ngff_cardem/include/card_pres.h | 22 +++ .../libboard/ngff_cardem/include/wwan_led.h | 20 +++ .../libboard/ngff_cardem/include/wwan_perst.h | 21 +++ .../libboard/ngff_cardem/product_string.txt | 1 + .../ngff_cardem/source/board_ngff_cardem.c | 159 +++++++++++++++++ .../libboard/ngff_cardem/source/card_pres.c | 76 ++++++++ .../libboard/ngff_cardem/source/sim_switch.c | 81 +++++++++ .../libboard/ngff_cardem/source/wwan_led.c | 93 ++++++++++ .../libboard/ngff_cardem/source/wwan_perst.c | 127 ++++++++++++++ firmware/libboard/simtrace/include/board.h | 2 +- firmware/libcommon/include/simtrace_usb.h | 1 + firmware/libcommon/source/mode_cardemu.c | 24 ++- host/contrib/99-simtrace2.rules | 2 + host/lib/usb_util.c | 1 + host/src/simtrace2-sniff.c | 1 + 19 files changed, 798 insertions(+), 8 deletions(-) create mode 100644 firmware/libboard/ngff_cardem/include/board.h create mode 100644 firmware/libboard/ngff_cardem/include/card_pres.h create mode 100644 firmware/libboard/ngff_cardem/include/wwan_led.h create mode 100644 firmware/libboard/ngff_cardem/include/wwan_perst.h create mode 100644 firmware/libboard/ngff_cardem/product_string.txt create mode 100644 firmware/libboard/ngff_cardem/source/board_ngff_cardem.c create mode 100644 firmware/libboard/ngff_cardem/source/card_pres.c create mode 100644 firmware/libboard/ngff_cardem/source/sim_switch.c create mode 100644 firmware/libboard/ngff_cardem/source/wwan_led.c create mode 100644 firmware/libboard/ngff_cardem/source/wwan_perst.c diff --git a/contrib/flash.py b/contrib/flash.py index 21903bbe..01fe7c9a 100755 --- a/contrib/flash.py +++ b/contrib/flash.py @@ -28,7 +28,8 @@ DEVICE_SIMTRACE = Device(usb_vendor_id=0x1d50, usb_product_id=0x60e3, name="SIMt DEVICE_QMOD = Device(usb_vendor_id=0x1d50, usb_product_id=0x4004, name="sysmoQMOD (Quad Modem)", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/qmod-cardem-dfu-latest.bin"}) DEVICE_OWHW = Device(usb_vendor_id=0x1d50, usb_product_id=0x4001, name="OWHW", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/owhw-cardem-dfu-latest.bin"}) DEVICE_OCTSIMTEST = Device(usb_vendor_id=0x1d50, usb_product_id=0x616d, name="OCTSIMTEST", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/octsimtest-cardem-dfu-latest.bin"}) -DEVICES = [DEVICE_SIMTRACE, DEVICE_QMOD, DEVICE_OCTSIMTEST] +DEVICE_NGFF_CARDEM = Device(usb_vendor_id=0x1d50, usb_product_id=0x616e, name="ngff-cardem", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/ngff_cardem-cardem-dfu-latest.bin"}) +DEVICES = [DEVICE_SIMTRACE, DEVICE_QMOD, DEVICE_OCTSIMTEST, DEVICE_NGFF_CARDEM] # which firmware does the SIMtrace USN interface subclass correspond FIRMWARE_SUBCLASS = {1: "trace", 2: "cardem"} diff --git a/contrib/simtrace.lua b/contrib/simtrace.lua index 68eb9610..82982652 100644 --- a/contrib/simtrace.lua +++ b/contrib/simtrace.lua @@ -62,6 +62,7 @@ end function usb_simtrace_protocol.init() local usb_product_dissectors = DissectorTable.get("usb.product") usb_product_dissectors:add(0x1d50616d, usb_simtrace_protocol) +usb_product_dissectors:add(0x1d50616e, usb_simtrace_protocol) -- DissectorTable.get("usb.bulk"):add(0xffff, usb_simtrace_protocol) end diff --git a/firmware/apps/cardem/main.c b/firmware/apps/cardem/main.c index a30a2119..95967ba6 100644 --- a/firmware/apps/cardem/main.c +++ b/firmware/apps/cardem/main.c @@ -71,8 +71,13 @@ static const conf_func config_func_ptrs[] = { .init = mode_cardemu_init, .exit = mode_cardemu_exit, .run = mode_cardemu_run, +#if defined (ngff_cardem) + .usart0_irq = mode_cardemu_usart1_irq, + .usart1_irq = mode_cardemu_usart0_irq, +#else .usart0_irq = mode_cardemu_usart0_irq, .usart1_irq = mode_cardemu_usart1_irq, +#endif }, #endif #ifdef HAVE_MITM diff --git a/firmware/libboard/ngff_cardem/include/board.h b/firmware/libboard/ngff_cardem/include/board.h new file mode 100644 index 00000000..8be7b7f9 --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/board.h @@ -0,0 +1,166 @@ +/* Osmocom ngff-cardem board definition + * + * (C) 2021 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#pragma once +#include "board_common.h" +#include "simtrace_usb.h" + +/** Name of the board */ +#define BOARD_NAME "NGFF-CARDEM" +/** Board definition */ +#define ngff_cardem + +/** oscillator used as main clock source (in Hz) */ +#define BOARD_MAINOSC 12000000 +/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ +#define BOARD_MCK 58000000 // 12.000 * 29 / 6 + +/** MCU pin connected to red LED */ +#define PIO_LED_RED PIO_PA17 +/** MCU pin connected to green LED */ +#define PIO_LED_GREEN PIO_PA18 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 +/** the green LED is actually red and used as indication for USIM1 */ +#define LED_USIM1 LED_GREEN + +/* USIM 2 interface (USART) */ +#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PIN_USIM2_IO {PIO_PA6, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PINS_ISO7816_USIM2 PIN_USIM2_CLK, PIN_USIM2_IO + +/* USIM 2 interface (TC) */ +#define PIN_USIM2_IO_TC {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PIN_USIM2_CLK_TC {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PINS_TC_USIM2 PIN_USIM2_IO_TC, PIN_USIM2_CLK_TC + +/* USIM 1 interface (USART) */ +#define PIN_USIM1_IO {PIO_PA22, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PIN_USIM1_CLK {PIO_PA23, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PINS_ISO7816_USIM1 PIN_USIM1_CLK, PIN_USIM1_IO + +/* USIM 1 interface (TC) */ +#define PIN_USIM1_IO_TC {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PIN_USIM1_CLK_TC {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PINS_TC_USIM1 PIN_USIM1_IO_TC, PIN_USIM1_CLK_TC + +#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} +#define PIN_USIM1_VCC {PIO_PB3, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT} + +#define PIN_USIM2_nRST {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} +//#define PIN_USIM2_VCC {PIO_PB2, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT} + +#define PINS_USIM1 PINS_TC_USIM1, PINS_ISO7816_USIM1, PIN_USIM1_nRST +#define PINS_USIM2 PINS_TC_USIM2, PINS_ISO7816_USIM2, PIN_USIM2_nRST + +/* from v3 and onwards only (!) */ +#define PIN_DET_USIM1_PRES {PIO_PA8, PIOA, ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_IT_EDGE} + +/* inputs reading the WWAN LED level */ +#define PIN_WWAN1 {PIO_PA15, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEGLITCH | PIO_IT_EDGE} +#define PINS_WWAN_IN { PIN_WWAN1 } + +#define PIN_MODEM_EN {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define PIN_N_MODEM_PWR_ON {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +/* outputs controlling RESET input of modems */ +#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define PINS_PERST { PIN_PERST1 } + +#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT} + +/* GPIO towards SPDT switches between real SIM and SAM3 */ +//#define PIN_SIM_SWITCH1 {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +//#define PIN_SIM_SWITCH2 {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP + +#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO +#define BOARD_USB_PRODUCT_ID USB_PRODUCT_NGFF_CARDEM +#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_NGFF_CARDEM +#define BOARD_USB_RELEASE 0x010 + +#define DETECT_VCC_BY_ADC +#define VCC_UV_THRESH_1V8 1500000 +#define VCC_UV_THRESH_3V VCC_UV_THRESH_1V8 + +#ifdef APPLICATION_cardem +#define HAVE_CARDEM +#define HAVE_BOARD_CARDINSERT +struct cardem_inst; +void board_set_card_insert(struct cardem_inst *ci, bool card_insert); +#endif + +#ifdef APPLICATION_trace +#define HAVE_SNIFFER +#endif + +/* Card I/O data signal input/output (I/O_SIM in schematic) */ +#define PIN_SIM_IO {PIO_PA6A_TXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* Card CLK clock input (CLK_SIM in schematic) */ +#define PIN_SIM_CLK {PIO_PA2B_SCK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +/* Card RST reset signal input (use as input since the phone will drive it) */ +#define PIN_SIM_RST_SNIFF {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_IT_EDGE} +/* Pins used to sniff phone-card communication */ +#define PINS_SIM_SNIFF PIN_SIM_IO, PIN_SIM_CLK, PIN_SIM_RST_SNIFF + +/* Pin to measure card I/O timing (to start measuring the ETU on I/O activity; connected I/O_SIM in schematic) */ +#define PIN_SIM_IO_INPUT {PIO_PA1B_TIOB0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +/* Pin used as clock input (to measure the ETU duration; connected to CLK_SIM in schematic) */ +#define PIN_SIM_CLK_INPUT {PIO_PA4B_TCLK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +/* Pins used to measure ETU timing (using timer counter) */ +#define PINS_TC PIN_SIM_IO_INPUT, PIN_SIM_CLK_INPUT + +//default state: NO uart connected, modem connected to physical sim, NO sim presence override, modem powers sim slot +#define pin_conn_usim1_default {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_usim2_default {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_mdm_sim_default {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_set_sim_det_default {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_st_sim_vdd_default {PIO_PB2, PIOB, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_en_mdm_sim_vdd_default {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} + +//cardem state: uart2 (!) connected, NO modem connected to physical sim, sim presence override, NOTHING powers sim slot +#define pin_conn_usim1_cem {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_usim2_cem {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_mdm_sim_cem {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_st_sim_vdd_cem {PIO_PB2, PIOB, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_en_mdm_sim_vdd_cem {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +//trace state: uart2 (!) connected, modem connected to physical sim, st powers sim slot +#define pin_conn_usim1_trace {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_usim2_trace {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_mdm_sim_trace {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_set_sim_det_trace {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_st_sim_vdd_trace {PIO_PB2, PIOB, ID_PIOB, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_mdm_sim_vdd_trace {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +#define PIN_MODEM_EN_off {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +#define PINS_SIM_DEFAULT pin_conn_usim1_default, pin_conn_usim2_default, pin_conn_mdm_sim_default, pin_conn_set_sim_det_default, PIN_N_MODEM_PWR_ON, PIN_MODEM_EN, pin_en_st_sim_vdd_default, pin_en_mdm_sim_vdd_default +#define PINS_SIM_CARDEM pin_conn_usim1_cem, pin_conn_usim2_cem, pin_conn_mdm_sim_cem, pin_en_mdm_sim_vdd_cem, pin_en_st_sim_vdd_cem// , pin_conn_set_sim_det_cem + +#define PINS_BUS_SNIFF pin_conn_usim1_trace, pin_conn_usim2_trace, pin_conn_mdm_sim_trace, pin_conn_set_sim_det_trace,PIN_MODEM_EN_off +#define PINS_PWR_SNIFF PIN_N_MODEM_PWR_ON, PIN_MODEM_EN, pin_en_st_sim_vdd_trace, pin_en_mdm_sim_vdd_trace diff --git a/firmware/libboard/ngff_cardem/include/card_pres.h b/firmware/libboard/ngff_cardem/include/card_pres.h new file mode 100644 index 00000000..81f06132 --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/card_pres.h @@ -0,0 +1,22 @@ +/* card presence utilities + * + * (C) 2016-2017 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#pragma once + +int is_card_present(int port); +int card_present_init(void); diff --git a/firmware/libboard/ngff_cardem/include/wwan_led.h b/firmware/libboard/ngff_cardem/include/wwan_led.h new file mode 100644 index 00000000..77887c7e --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/wwan_led.h @@ -0,0 +1,20 @@ +/* Code to read/track the status of the WWAN LEDs of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#pragma once + +int wwan_led_active(int wwan); +int wwan_led_init(void); diff --git a/firmware/libboard/ngff_cardem/include/wwan_perst.h b/firmware/libboard/ngff_cardem/include/wwan_perst.h new file mode 100644 index 00000000..c934afce --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/wwan_perst.h @@ -0,0 +1,21 @@ +/* Code to control the PERST lines of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#pragma once + +int wwan_perst_set(int modem_nr, int active); +int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms); +int wwan_perst_init(void); diff --git a/firmware/libboard/ngff_cardem/product_string.txt b/firmware/libboard/ngff_cardem/product_string.txt new file mode 100644 index 00000000..09a33c6a --- /dev/null +++ b/firmware/libboard/ngff_cardem/product_string.txt @@ -0,0 +1 @@ +ngff-cardem diff --git a/firmware/libboard/ngff_cardem/source/board_ngff_cardem.c b/firmware/libboard/ngff_cardem/source/board_ngff_cardem.c new file mode 100644 index 00000000..0ac9cd87 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/board_ngff_cardem.c @@ -0,0 +1,159 @@ +/* sysmocom ngff-cardem application code + * + * (C) 2021 Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#include "board.h" +#include "simtrace.h" +#include "utils.h" +#include "led.h" +#include "wwan_led.h" +#include "wwan_perst.h" +#include "sim_switch.h" +#include "boardver_adc.h" +#include "card_pres.h" +#include +#include "usb_buf.h" + +/* array of generated USB Strings */ +extern unsigned char *usb_strings[]; + +/* returns '1' in case we should break any endless loop */ +void board_exec_dbg_cmd(int ch) +{ + switch (ch) { + case '?': + printf("\t?\thelp\n\r"); + printf("\tR\treset SAM3\n\r"); + printf("\tl\tswitch off LED 1\n\r"); + printf("\tL\tswitch on LED 1\n\r"); + printf("\tg\tswitch off LED 2\n\r"); + printf("\tG\tswitch on LED 2\n\r"); + printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r"); + printf("\t!\tSwitch Channel A from physical -> remote\n\r"); + printf("\tt\t(pseudo)talloc report\n\r"); + break; + case 'R': + printf("Asking NVIC to reset us\n\r"); + USBD_Disconnect(); + NVIC_SystemReset(); + break; + case 'l': + led_blink(LED_GREEN, BLINK_ALWAYS_OFF); + printf("LED 1 switched off\n\r"); + break; + case 'L': + led_blink(LED_GREEN, BLINK_ALWAYS_ON); + printf("LED 1 switched on\n\r"); + break; + case 'g': + led_blink(LED_RED, BLINK_ALWAYS_OFF); + printf("LED 2 switched off\n\r"); + break; + case 'G': + led_blink(LED_RED, BLINK_ALWAYS_ON); + printf("LED 2 switched on\n\r"); + break; + case '1': + printf("Resetting Modem\n\r"); + wwan_perst_do_reset_pulse(0, 300); + break; + case '!': + sim_switch_use_physical(0, 0); + break; + case 't': + talloc_report(NULL, stdout); + break; + default: + printf("Unknown command '%c'\n\r", ch); + break; + } +} + +void board_main_top(void) +{ +#ifndef APPLICATION_dfu + usb_buf_init(); + + wwan_led_init(); + wwan_perst_init(); + sim_switch_init(); +#endif + + /* Obtain the circuit board version (currently just prints voltage) */ + get_board_version_adc(); +#ifndef APPLICATION_dfu + /* Initialize checking for card insert/remove events */ + card_present_init(); +#endif + wwan_perst_set(0, 0); +} + +static int uart_has_loopback_jumper(void) +{ + unsigned int i; + const Pin uart_loopback_pins[] = { + {PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}, + {PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + }; + + /* Configure UART pins as I/O */ + PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins)); + + /* Send pattern over UART TX and check if it is received on RX + * If the loop doesn't get interrupted, RxD always follows TxD and thus a + * loopback jumper has been placed on RxD/TxD, and we will boot + * into DFU unconditionally + */ + int has_loopback_jumper = 1; + for (i = 0; i < 10; i++) { + /* Set TxD high; abort if RxD doesn't go high either */ + PIO_Set(&uart_loopback_pins[1]); + if (!PIO_Get(&uart_loopback_pins[0])) { + has_loopback_jumper = 0; + break; + } + /* Set TxD low, abort if RxD doesn't go low either */ + PIO_Clear(&uart_loopback_pins[1]); + if (PIO_Get(&uart_loopback_pins[0])) { + has_loopback_jumper = 0; + break; + } + } + + /* Put pins back to UART mode */ + const Pin uart_pins[] = {PINS_UART}; + PIO_Configure(uart_pins, PIO_LISTSIZE(uart_pins)); + + return has_loopback_jumper; +} + +int board_override_enter_dfu(void) +{ + /* If the loopback jumper is set, we enter DFU mode */ + if (uart_has_loopback_jumper()) + return 1; + + return 0; +} + + static const Pin deton = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; + static const Pin detoff = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}; + +void board_set_card_insert(struct cardem_inst *ci, bool card_insert) +{ + PIO_Configure(card_insert ? &deton : &detoff, 1); +} \ No newline at end of file diff --git a/firmware/libboard/ngff_cardem/source/card_pres.c b/firmware/libboard/ngff_cardem/source/card_pres.c new file mode 100644 index 00000000..7d6c4834 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/card_pres.c @@ -0,0 +1,76 @@ +/* card presence utilities + * + * (C) 2016-2021 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#include +#include "board.h" +#include "utils.h" +#include "card_pres.h" + +#define NUM_CARDPRES 1 + +#define TIMER_INTERVAL_MS 500 + +static const Pin pin_cardpres[NUM_CARDPRES] = { PIN_DET_USIM1_PRES }; +static int last_state[NUM_CARDPRES] = { -1 }; +static struct osmo_timer_list cardpres_timer; + +/* Determine if a SIM card is present in the given slot */ +int is_card_present(int port) +{ + const Pin *pin; + int present; + + if (port < 0 || port >= NUM_CARDPRES) + return -1; + pin = &pin_cardpres[port]; + + + /* high active here */ + present = PIO_Get(pin); + + return present; +} + +static void cardpres_tmr_cb(void *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pin_cardpres); i++) { + int state = is_card_present(i); + if (state != last_state[i]) { + TRACE_INFO("%u: Card Detect Status %d -> %d\r\n", i, last_state[i], state); + /* FIXME: report to USB host */ + last_state[i] = state; + } + } + + osmo_timer_schedule(&cardpres_timer, 0, TIMER_INTERVAL_MS*1000); +} + +int card_present_init(void) +{ + unsigned int i; + + PIO_Configure(pin_cardpres, ARRAY_SIZE(pin_cardpres)); + + /* start timer */ + cardpres_timer.cb = cardpres_tmr_cb; + osmo_timer_schedule(&cardpres_timer, 0, TIMER_INTERVAL_MS*1000); + + return 2; +} diff --git a/firmware/libboard/ngff_cardem/source/sim_switch.c b/firmware/libboard/ngff_cardem/source/sim_switch.c new file mode 100644 index 00000000..eb2d305f --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/sim_switch.c @@ -0,0 +1,81 @@ +/* Code to switch between local (physical) and remote (emulated) SIM + * + * (C) 2015-2017 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +#include "board.h" +#include "trace.h" +#include "led.h" +#include "sim_switch.h" + +//uart12bus 2-20e pa20 +//uart22bus 1-20e pa28 +//usim2bus 1-10e pa0 pivot +//sim det 2-10e pa13 + +static const Pin pins_default[] = {PINS_SIM_DEFAULT}; +static const Pin pins_cem[] = {PINS_SIM_CARDEM}; + +static int initialized = 0; + +int sim_switch_use_physical(unsigned int nr, int physical) +{ + const Pin pin = PIN_MODEM_EN;// PIN_N_MODEM_PWR_ON; + enum led led; + + if (!initialized) { + TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n"); + sim_switch_init(); + } + + TRACE_INFO("Modem %d: %s SIM\n\r", nr, + physical ? "physical" : "virtual"); + + switch (nr) { + case 0: + led = LED_USIM1; + break; + + default: + TRACE_ERROR("Invalid SIM%u\n\r", nr); + return -1; + } + + if (physical) { + TRACE_INFO("%u: Use local/physical SIM\r\n", nr); + PIO_Configure(pins_default, PIO_LISTSIZE(pins_default)); + led_blink(led, BLINK_ALWAYS_ON); + } else { + TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr); + PIO_Configure(pins_cem, PIO_LISTSIZE(pins_cem)); + led_blink(led, BLINK_ALWAYS_OFF); + } + + /* just power cycle the modem because this circumvents weird issues with unreliable signals */ + PIO_Clear(&pin); + mdelay(200); + PIO_Set(&pin); + + + return 0; +} + +int sim_switch_init(void) +{ + PIO_Configure(pins_default, PIO_LISTSIZE(pins_default)); + initialized = 1; + return 1; +} diff --git a/firmware/libboard/ngff_cardem/source/wwan_led.c b/firmware/libboard/ngff_cardem/source/wwan_led.c new file mode 100644 index 00000000..36eb0ecb --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/wwan_led.c @@ -0,0 +1,93 @@ +/* Code to read/track the status of the WWAN LEDs of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +/* Depending on the board this is running on, it might be possible + * for the controller to read the status of the WWAN LED output lines of + * the cellular modem. If the board supports this, it sets the + * PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file. + */ +#include "board.h" +#include "wwan_led.h" + +#ifdef PIN_WWAN1 +static const Pin pin_wwan1 = PIN_WWAN1; + +static void wwan1_irqhandler(const Pin *pPin) +{ + int active = wwan_led_active(0); + + TRACE_INFO("0: WWAN LED %u\r\n", active); + + /* TODO: notify host via USB */ +} +#endif + +#ifdef PIN_WWAN2 +static const Pin pin_wwan2 = PIN_WWAN2; + +static void wwan2_irqhandler(const Pin *pPin) +{ + int active = wwan_led_active(1); + TRACE_INFO("1: WWAN LED %u\r\n", active); + + /* TODO: notify host via USB */ +} +#endif + +/* determine if a given WWAN led is currently active or not */ +int wwan_led_active(int wwan) +{ + const Pin *pin; + int active; + + switch (wwan) { +#ifdef PIN_WWAN1 + case 0: + pin = &pin_wwan1; + break; +#endif +#ifdef PIN_WWAN2 + case 1: + pin = &pin_wwan2; + break; +#endif + default: + return -1; + } + + active = PIO_Get(pin) ? 0 : 1; + return active; +} + +int wwan_led_init(void) +{ + int num_leds = 0; + +#ifdef PIN_WWAN1 + PIO_Configure(&pin_wwan1, 1); + PIO_ConfigureIt(&pin_wwan1, wwan1_irqhandler); + PIO_EnableIt(&pin_wwan1); + num_leds++; +#endif + +#ifdef PIN_WWAN2 + PIO_Configure(&pin_wwan2, 1); + PIO_ConfigureIt(&pin_wwan2, wwan2_irqhandler); + PIO_EnableIt(&pin_wwan2); + num_leds++; +#endif + return num_leds; +} diff --git a/firmware/libboard/ngff_cardem/source/wwan_perst.c b/firmware/libboard/ngff_cardem/source/wwan_perst.c new file mode 100644 index 00000000..95a7c7b8 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/wwan_perst.c @@ -0,0 +1,127 @@ +/* Code to control the PERST lines of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + */ +/* Depending on the board this is running on, it might be possible + * for the controller to set the status of the PERST input line of + * the cellular modem. If the board supports this, it sets the + * PIN_PERST1 and/or PIN_PERST2 defines in its board.h file. + */ +#include "board.h" +#include "trace.h" +#include "wwan_perst.h" +#include + +struct wwan_perst { + uint8_t idx; + const Pin pin; + struct osmo_timer_list timer; +}; + +#ifdef PIN_PERST1 +static struct wwan_perst perst1 = { + .idx = 0, + .pin = PIN_PERST1, +}; +#endif + +#ifdef PIN_PERST2 +static struct wwan_perst perst2 = { + .idx = 1, + .pin = PIN_PERST2, +}; +#endif + +static int initialized = 0; + +static void perst_tmr_cb(void *data) +{ + struct wwan_perst *perst = data; + /* release the (low-active) reset */ + TRACE_INFO("%u: De-asserting modem reset\r\n", perst->idx); + PIO_Clear(&perst->pin); +} + +static struct wwan_perst *get_perst_for_modem(int modem_nr) +{ + if (!initialized) { + TRACE_ERROR("Somebody forgot to call wwan_perst_init()\r\n"); + wwan_perst_init(); + } + + switch (modem_nr) { +#ifdef PIN_PERST1 + case 0: + return &perst1; +#endif +#ifdef PIN_PERST2 + case 1: + return &perst2; +#endif + default: + return NULL; + } +} + +int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms) +{ + struct wwan_perst *perst = get_perst_for_modem(modem_nr); + if (!perst) + return -1; + + TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr); + PIO_Set(&perst->pin); + osmo_timer_schedule(&perst->timer, duration_ms/1000, (duration_ms%1000)*1000); + + return 0; +} + +int wwan_perst_set(int modem_nr, int active) +{ + struct wwan_perst *perst = get_perst_for_modem(modem_nr); + if (!perst) + return -1; + + osmo_timer_del(&perst->timer); + if (active) { + TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr); + PIO_Set(&perst->pin); + } else { + TRACE_INFO("%u: De-asserting modem reset\r\n", modem_nr); + PIO_Clear(&perst->pin); + } + + return 0; +} + +int wwan_perst_init(void) +{ + int num_perst = 0; +#ifdef PIN_PERST1 + PIO_Configure(&perst1.pin, 1); + perst1.timer.cb = perst_tmr_cb; + perst1.timer.data = (void *) &perst1; + num_perst++; +#endif + +#ifdef PIN_PERST2 + PIO_Configure(&perst2.pin, 1); + perst2.timer.cb = perst_tmr_cb; + perst2.timer.data = (void *) &perst2; + num_perst++; +#endif + initialized = 1; + return num_perst; +} diff --git a/firmware/libboard/simtrace/include/board.h b/firmware/libboard/simtrace/include/board.h index 4b6eda22..be18f64d 100644 --- a/firmware/libboard/simtrace/include/board.h +++ b/firmware/libboard/simtrace/include/board.h @@ -40,7 +40,7 @@ /** green LED pin definition */ #define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} /** LEDs pin definition */ -#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN /** index for red LED in LEDs pin definition array */ #define LED_NUM_RED 0 /** index for green LED in LEDs pin definition array */ diff --git a/firmware/libcommon/include/simtrace_usb.h b/firmware/libcommon/include/simtrace_usb.h index a232ac5d..7bf401c7 100644 --- a/firmware/libcommon/include/simtrace_usb.h +++ b/firmware/libcommon/include/simtrace_usb.h @@ -26,6 +26,7 @@ #define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */ #define USB_PRODUCT_SIMTRACE2 0x60e3 #define USB_PRODUCT_OCTSIMTEST 0x616d +#define USB_PRODUCT_NGFF_CARDEM 0x616e /* USB proprietary class */ #define USB_CLASS_PROPRIETARY 0xff diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index 2440ec5e..4a0b862f 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -39,9 +39,21 @@ static const Pin pins_cardsim[] = PINS_CARDSIM; #endif /* UART pins */ +#if defined(ngff_cardem) +static const Pin pins_usim1[] = {PINS_USIM2}; +static const Pin pin_usim1_rst = PIN_USIM2_nRST; +#define FIRST_USART_BASE USART0 +#define FIRST_USART_ID ID_USART0 +#define FIRST_USART_IRQ USART0_IRQn +#else static const Pin pins_usim1[] = {PINS_USIM1}; static const Pin pin_usim1_rst = PIN_USIM1_nRST; +#define FIRST_USART_BASE USART1 +#define FIRST_USART_ID ID_USART1 +#define FIRST_USART_IRQ USART1_IRQn +#endif static const Pin pin_usim1_vcc = PIN_USIM1_VCC; + #ifdef PIN_USIM1_IO_DIR static const Pin pin_io_dir = PIN_USIM1_IO_DIR; #endif @@ -85,8 +97,8 @@ struct cardem_inst cardem_inst[] = { { .num = 0, .usart_info = { - .base = USART1, - .id = ID_USART1, + .base = FIRST_USART_BASE, + .id = FIRST_USART_ID, .state = USART_RCV }, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT, @@ -569,7 +581,7 @@ void mode_cardemu_init(void) /* configure USART as ISO-7816 slave (e.g. card) */ ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); - NVIC_EnableIRQ(USART1_IRQn); + NVIC_EnableIRQ(FIRST_USART_IRQ); PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); PIO_EnableIt(&pin_usim1_rst); @@ -627,9 +639,9 @@ void mode_cardemu_exit(void) PIO_DisableIt(&pin_usim1_rst); PIO_DisableIt(&pin_usim1_vcc); - NVIC_DisableIRQ(USART1_IRQn); - USART_SetTransmitterEnabled(USART1, 0); - USART_SetReceiverEnabled(USART1, 0); + NVIC_DisableIRQ(FIRST_USART_IRQ); + USART_SetTransmitterEnabled(FIRST_USART_BASE, 0); + USART_SetReceiverEnabled(FIRST_USART_BASE, 0); #ifdef CARDEMU_SECOND_UART PIO_DisableIt(&pin_usim2_rst); diff --git a/host/contrib/99-simtrace2.rules b/host/contrib/99-simtrace2.rules index b5763897..5ae04e20 100644 --- a/host/contrib/99-simtrace2.rules +++ b/host/contrib/99-simtrace2.rules @@ -18,6 +18,8 @@ ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4003", GROUP="plugdev" ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4004", GROUP="plugdev" # sysmocom OCTSIMTEST ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="616d", GROUP="plugdev" +# ngff-cardem +ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="616e", GROUP="plugdev" # All done LABEL="simtrace2_rules_end" diff --git a/host/lib/usb_util.c b/host/lib/usb_util.c index 4d3b2b97..872d1853 100644 --- a/host/lib/usb_util.c +++ b/host/lib/usb_util.c @@ -33,5 +33,6 @@ const struct dev_id osmo_st2_compatible_dev_ids[] = { { USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 }, { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 }, { USB_VENDOR_OPENMOKO, USB_PRODUCT_OCTSIMTEST }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_NGFF_CARDEM }, { 0, 0 } }; diff --git a/host/src/simtrace2-sniff.c b/host/src/simtrace2-sniff.c index 47d9e775..c44029a4 100644 --- a/host/src/simtrace2-sniff.c +++ b/host/src/simtrace2-sniff.c @@ -315,6 +315,7 @@ static const struct option opts[] = { /* Known USB device with SIMtrace firmware supporting sniffer */ static const struct dev_id compatible_dev_ids[] = { { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_NGFF_CARDEM }, { 0, 0 } };