diff --git a/firmware/libboard/common/include/sim_switch.h b/firmware/libboard/common/include/sim_switch.h new file mode 100644 index 00000000..16c5aa33 --- /dev/null +++ b/firmware/libboard/common/include/sim_switch.h @@ -0,0 +1,4 @@ +#pragma once + +int sim_switch_use_physical(unsigned int nr, int physical); +int sim_switch_init(void); diff --git a/firmware/libboard/common/source/sim_switch.c b/firmware/libboard/common/source/sim_switch.c new file mode 100644 index 00000000..49e6cea6 --- /dev/null +++ b/firmware/libboard/common/source/sim_switch.c @@ -0,0 +1,64 @@ +/* Code to switch between local (physical) and remote (emulated) SIM */ + +#include "board.h" +#include "trace.h" +#include "sim_switch.h" + +#ifdef PIN_SIM_SWITCH1 +static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; +#endif +#ifdef PIN_SIM_SWITCH2 +static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; +#endif + +static int initialized = 0; + +int sim_switch_use_physical(unsigned int nr, int physical) +{ + const Pin *pin; + + 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) { +#ifdef PIN_SIM_SWITCH1 + case 1: + pin = &pin_conn_usim1; + break; +#endif +#ifdef PIN_SIM_SWITCH2 + case 2: + pin = &pin_conn_usim2; + break; +#endif + default: + TRACE_ERROR("Invalid SIM%u\n\r", nr); + return -1; + } + + if (physical) + PIO_Clear(pin); + else + PIO_Set(pin); + + return 0; +} + +int sim_switch_init(void) +{ + int num_switch = 0; +#ifdef PIN_SIM_SWITCH1 + PIO_Configure(&pin_conn_usim1, 1); + num_switch++; +#endif +#ifdef PIN_SIM_SWITCH2 + PIO_Configure(&pin_conn_usim2, 1); + num_switch++; +#endif + return num_switch; +} diff --git a/firmware/libboard/qmod/include/board.h b/firmware/libboard/qmod/include/board.h index 082d254d..d49ff9d6 100644 --- a/firmware/libboard/qmod/include/board.h +++ b/firmware/libboard/qmod/include/board.h @@ -56,6 +56,10 @@ #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 diff --git a/firmware/libboard/qmod/source/board_qmod.c b/firmware/libboard/qmod/source/board_qmod.c index 889d31ec..54983d7f 100644 --- a/firmware/libboard/qmod/source/board_qmod.c +++ b/firmware/libboard/qmod/source/board_qmod.c @@ -6,6 +6,7 @@ #include "utils.h" #include "wwan_led.h" #include "wwan_perst.h" +#include "sim_switch.h" #include "boardver_adc.h" #include "card_pres.h" #include "osmocom/core/timer.h" @@ -17,37 +18,9 @@ static const Pin pin_1234_detect = {PIO_PA14, PIOA, ID_PIOA, PIO_INPUT, PIO_PULL static const Pin pin_peer_rst = {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; static const Pin pin_peer_erase = {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; -static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; -static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; - /* array of generated USB Strings */ extern unsigned char *usb_strings[]; -static void qmod_use_physical_sim(unsigned int nr, int physical) -{ - const Pin *pin; - - TRACE_INFO("Modem %d: %s SIM\n\r", nr, - physical ? "physical" : "virtual"); - - switch (nr) { - case 1: - pin = &pin_conn_usim1; - break; - case 2: - pin = &pin_conn_usim2; - break; - default: - TRACE_ERROR("Invalid SIM%u\n\r", nr); - return; - } - - if (physical) - PIO_Clear(pin); - else - PIO_Set(pin); -} - static int qmod_sam3_is_12(void) { if (PIO_Get(&pin_1234_detect) == 0) @@ -218,10 +191,10 @@ void board_exec_dbg_cmd(int ch) wwan_perst_do_reset_pulse(2, 300); break; case '!': - qmod_use_physical_sim(1, 0); + sim_switch_use_physical(1, 0); break; case '@': - qmod_use_physical_sim(2, 0); + sim_switch_use_physical(2, 0); break; default: if (!qmod_sam3_is_12()) @@ -238,6 +211,7 @@ void board_main_top(void) wwan_led_init(); wwan_perst_init(); + sim_switch_init(); /* make sure we can detect whether running in ST12 or ST34 */ PIO_Configure(&pin_1234_detect, 1); @@ -250,8 +224,6 @@ void board_main_top(void) } PIO_Configure(&pin_peer_rst, 1); PIO_Configure(&pin_peer_erase, 1); - PIO_Configure(&pin_conn_usim1, 1); - PIO_Configure(&pin_conn_usim2, 1); i2c_pin_init(); if (qmod_sam3_is_12()) { diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index 2e50134b..4f1c3dda 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -12,6 +12,7 @@ #include "usb_buf.h" #include "simtrace_prot.h" #include "wwan_perst.h" +#include "sim_switch.h" #define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__) @@ -521,6 +522,21 @@ static int usb_command_modem_reset(struct msgb *msg, struct cardem_inst *ci) return 0; } +static int usb_command_sim_select(struct msgb *msg, struct cardem_inst *ci) +{ + struct st_modem_sim_select *mss = msg->l2h; + + if (msgb_l2len(msg) < sizeof(*mss)) + return -1; + + if (mss->remote_sim) + sim_switch_use_physical(ci->num, 0); + else + sim_switch_use_physical(ci->num, 1); + + return 0; +} + /* handle a single USB command as received from the USB host */ static void dispatch_usb_command_modem(struct msgb *msg, struct cardem_inst *ci) { @@ -532,6 +548,7 @@ static void dispatch_usb_command_modem(struct msgb *msg, struct cardem_inst *ci) usb_command_modem_reset(msg, ci); break; case SIMTRACE_MSGT_DT_MODEM_SIM_SELECT: + usb_command_sim_select(msg, ci); break; case SIMTRACE_MSGT_BD_MODEM_STATUS: break;