227 Commits
0.2 ... 0.5.1

Author SHA1 Message Date
Harald Welte
e07640c35a tag debian release 0.5.1
Change-Id: Id6559b1019353815eea9f6653b6560e9a8aab23a
2018-08-26 11:51:13 +02:00
Harald Welte
82b628524f simtrace2-sniff: Fix build with released libosmocore versions
There's still no released libosmocore defining the GSMTAP_TYPE_SIM
sub-types (Change-Id: I5bd0dff5a4a90cfe96d9c4f3dec6657e1d85bf7a
dated Jul 26, 2018).

Let's make sure users don't need an unreleased version of the library
if it's only about a few #defines that we can just copy here for
backwards compatibility.

Change-Id: I2fd9e14873711d60f194bb404420bbfbb0a00f48
2018-08-26 11:43:12 +02:00
Harald Welte
cb78b55c26 Revert "debian/control: Depend on libosmocore >= 0.12.1"
This reverts commit 77ff745cca.

libosmocore 0.12.1 is not recent enough, I misread the 'gitk' output.

Change-Id: I87a8e5bbb4aea0c991abe5372f840d76f17378eb
2018-08-26 11:43:11 +02:00
Harald Welte
77ff745cca debian/control: Depend on libosmocore >= 0.12.1
Only this version includes the GSMTAP_SIM_ATR and GSMTAP_SIM_APDU
definitions.

Change-Id: I988cad56aed755af416fc7f23822dcf0229dbb7d
2018-08-26 10:52:46 +02:00
Harald Welte
bd9d94994d v0.5 debian package release
Change-Id: Iaf56c03f966a5dfc8b750d926f0429223aeec54e
2018-08-26 10:37:39 +02:00
Harald Welte
95fac3aeab Add Debian packaging rules
Change-Id: Iece115e4dde87bff5dc36286668f50de0abdcb9e
2018-08-26 10:20:05 +02:00
Harald Welte
c17bf77ecc owhw: Fix cardem GPIO initialization pointer value
This fixes a bug, identified by the below compiler warning:

libboard/owhw/source/owhw.c: In function 'cardsim_gpio_init':
libboard/owhw/source/owhw.c:39:16: warning: passing argument 1 of 'PIO_Configure' from incompatible pointer type [-Wincompatible-pointer-types]
  PIO_Configure(&pins_cardsim, ARRAY_SIZE(pins_cardsim));
                ^
In file included from ./atmel_softpack_libraries/libchip_sam3s/chip.h:45:0,
                 from libboard/owhw/source/owhw.c:20:
./atmel_softpack_libraries/libchip_sam3s/include/pio.h:189:16: note: expected 'const Pin * {aka const struct _Pin *}' but argument is of type 'const Pin (*)[2] {aka const struct _Pin (*)[2]}'
 extern uint8_t PIO_Configure( const Pin *list, uint32_t size ) ;
                ^~~~~~~~~~~~~

Change-Id: I4c1de66c0b8475bb355b1d128f6ec88b2f2a7fcf
2018-08-26 10:20:05 +02:00
Harald Welte
c394109964 firmware: Enable -Wformat and resolve all related compiler warnings
There have been tons of format-string related bugs in our code which
we never discovered due to disabling -Wformat.  Let's fix that.

Change-Id: I5ec466361bcc526fac1f4897673264ee5af3458b
2018-08-26 10:20:05 +02:00
Harald Welte
888f196595 add master Makefile to build firmware and host tools
Change-Id: I715d3fdaff9d80673bb2208ea9d56637f4e459af
2018-08-26 10:20:02 +02:00
Harald Welte
f7f61cd10f Makefiles: Add "make install" target
Change-Id: Ic6835ce55930c60f909e140878c4abab8628e077
2018-08-26 10:09:43 +02:00
Harald Welte
0e95f53588 host: Fix "make clean": remove simtrace2-sniff
Change-Id: Ib233b6a4b3976286196da95036cadcf2d3382f77
2018-08-26 09:54:55 +02:00
Kévin Redon
76ef811a4e jenkins: add simtrace/trace to the builds
trace is now stable enough on simtrace to be built and uploaded.

Change-Id: I157fff9930d03a7ec52ecac4a1be0511ea66c010
2018-08-07 19:01:25 +02:00
Kévin Redon
fecfa2aa51 jenkins: clean after upload
the upload failed because after the firmware were built (make),
they where removed (make clean).
now they are removed only after the upload.

Change-Id: Ie4421a6fa9207eb541107de9c14f265626f6be96
2018-08-07 17:51:48 +02:00
Kévin Redon
c428516efa qmod: error on EEPROM erase fail
repeating the EEPROM erase (byte write) in case of byte write failure
could lead in an infinite loop.
log the error an return error code instead.

Change-Id: Id6f3654d877ca772ba04237da91a6e86e3f441ec
2018-08-07 15:14:37 +00:00
Kévin Redon
37e7861c4d jenkins: fix publish
the script argument was not saved in the publish variable used later
to decide if publishing/uploading is needed.

Change-Id: Ic768a8e96e5e4d72acf3979da1412d683f79ec55
2018-08-07 12:09:49 +02:00
Kévin Redon
ff3d84922d USB: increase USB reset time
USB reset can be signaled by pulling low USB D+ for at least 10 ms,
according to the USB specification. This force a re-enumeration.
This time is increased to 20 ms to work with more USB HUBs.

Some SAM3S based board have external D+ pull-up mechanism (such as
SIMtrace) which needs to be used to pull D+ low.
This is a legacy mechanism from SAM7S history.
This mechanism is not required anymore on the SAM3S, and the qmod
does not use it. When the USB HAL is suspended, the transceiver is
disabled, causing D+ and D- to be pulled low. Then the HAL is activated
again. This is particularly required when DFU is started (and
enumerated), and after flashing the SAM3S switched to the main
application (without reset), so it can properly re-enumerate.

This board difference is now defined on the board header.

Change-Id: I9b58d8101c2fcf5595026b675728826af26127a3
2018-08-07 12:09:49 +02:00
Harald Welte
9547e419eb qmod: Add 'e' command for erasing the EEPROM
Change-Id: Id7cb0db568dd3e9d796829bf0019d63048612998
2018-08-07 10:00:49 +00:00
Kévin Redon
8daba9cc9a gcc: fix warning
moving the define after the header fixes the following warning:
                 from ./atmel_softpack_libraries/libchip_sam3s/source/exceptions.c:46:
libcommon/include/stdio.h:63:12: warning: redundant redeclaration of 'printf_sync' [-Wredundant-decls]
 signed int printf_sync(const char *pFormat, ...);
            ^~~~~~~~~~~
./atmel_softpack_libraries/libchip_sam3s/source/exceptions.c:45:16: note: previous declaration of 'printf_sync' was here
 #define printf printf_sync
                ^~~~~~~~~~~
libcommon/include/stdio.h:51:12: note: in expansion of macro 'printf'
 signed int printf(const char *pFormat, ...);

Change-Id: I21a8de325e8f8b91297dd157f2d6a0f64434bb28
2018-08-06 16:23:33 +02:00
Kévin Redon
d5f583da60 jenkins: add build uploads
firmware binaries should be uploaded to
https://ftp.osmocom.org/binaries/simtrace2/firmware/
this directory wiki be documented in the SIMtrace 2 wiki for users
to get the latest firmware images without having to cross-compile
themselves.

Change-Id: I589531f59e54a0997b012bdd91e3bef9f847f517
2018-08-06 15:57:43 +02:00
Kévin Redon
04ccb770fd remsim: fix USB hanging USB transfer
After a couple of seconds of USB data exchange between remsim and
cardem, the USB transfer hangs.
On host side (remsim) I can see the USB BULK IN request.
On device side (cardem) I see that data has been submitted and
"sent" over USB, but on wireshark with USBmon I don't see the
corresponding USB BULK IN response.
When exiting remsim or just after powering of qmod (causing an
error in remsim) the USB BULK IN is show in wireshark. Thus it
must have been in a buffer, but not read by libusb_bulk_transfer.
By shortening the timeout a new libusb_bulk_transfer is made more
frequently, and the data gets read successfully.

T;his change also fixes the URB data display.

Change-Id: I1d124a41cc90893506933f6d76dc7331e52a74f9
2018-08-04 11:16:15 +02:00
Kévin Redon
910e6830b9 cardem (minor): trace tx data send over USB
Change-Id: I69cef43dd5a78e9f82cc045cdb90c326b03d1f68
2018-08-04 11:16:15 +02:00
Kévin Redon
9cccb2bab5 add libosmcore utilities
osmo_hexdump is particularly useful.
previously it was only defined, but not implemented.
this cause random behaviour upon call, often resulting in
memory corruption.

Change-Id: Ifd9120fa951f41693903fb657d10826959f1599f
2018-08-04 11:16:15 +02:00
Kévin Redon
8a4fba5ea2 cardem: add state name in trace
this helps reading the output while debugging quite a lot

Change-Id: Idf301e09cf14e2412e29dcb252563bc6e4e5c630
2018-08-04 11:16:15 +02:00
Kévin Redon
1b39fd31ee cardem (minor): remove to verbose log trace
Change-Id: Ie43a33af3728c0700f71527ca75d909a9ebd2529
2018-08-04 11:16:15 +02:00
Kévin Redon
0f4abf5eaa cardem: minor typo fix in comment
Change-Id: Ib1dee95e15db1c6bb3b45920d7c1a567e2ba474b
2018-08-04 11:16:15 +02:00
Kévin Redon
1836ac0761 add synchronous UART transmission and use it in exceptions
The default ISR (particularly the HardFault handler) print information,
but this information was not displayed on the console because the UART
IRQ is lower than some default blocking IRQ.
Allowing to set synchronous transfer corrects this.

The underlying Atmel exception library had to be modified to use the
synchronous output.

Making UART_PutChar always synchronous when called from an ISR is not
desired because we use TRACE_ macros is some ISR. The synchronous
output must be set explicitly.

Change-Id: I1b4ace5185cf2dc32684934ed12bf6a8682e9bad
2018-08-04 11:16:13 +02:00
Kévin Redon
dd36d9b010 sniff: send incomplete TPDU when reset is asserted
Change-Id: I8d7e4d604cded535e40d27c2be872268e0f24c20
2018-08-01 10:35:55 +02:00
Kévin Redon
8b8e58b00e cardem: use TC2 as WI and update WT after ATR
Change-Id: I3e51b16d557bc664f87563e1a3dce6642de474d2
2018-07-30 18:19:11 +02:00
Kévin Redon
8f70c3eb1f remsim: fix payload overwriting
The slot number is in the header, and correctly set in st_push_hdr.
Setting the slot in st_slot_tx_msg will overwrite the payload data.
This caused bytes three of the ATR to be changed from 0x96 to 0x00,
corrupting the ATR. This corruption is caught by the ATR checksum,
and the modem would reset the card (2 additional times) to try to
get correct ATR.

Change-Id: If971699993617fc50557d20582c344ea06645a3f
2018-07-30 15:03:55 +02:00
Kévin Redon
ebe672e926 cardem: use TC_ETU to trigger ATR sending
this changes how ATR is handled.
the ATR is also printed when set (as important debug information).
the test is also updated to correspond to the new mechanism (
simulating the timeout before sending the ATR)

Change-Id: I69df797e2feadffa9f5f977cb71b69386cee7cd0
2018-07-30 15:02:35 +02:00
Kévin Redon
d8ebd6ab77 cardem: increase watchdog to 2 seconds
a lot of the procedures are done in ISRs, but the watchdog is only
reset in the main loop.
this causes frequent reset, particularly at the beginning were
states have to the initialized.

Change-Id: Iad364444fca9d18f9a8cf47d5e0840ccd7bac2ef
2018-07-29 09:58:31 +02:00
Kévin Redon
738a04aefb cardem: show detailed reset cause
this helps detecting when a reset was due to the watchdog

Change-Id: I2d59c2f2c8fe9e559eddfafacf25879263ef81ff
2018-07-29 09:58:31 +02:00
Kévin Redon
2a44dc598d sniff: increase debug output
Change-Id: Ife0bbcf4a25aaa445a36768c00004e6e0d9a4947
2018-07-29 09:58:28 +02:00
Kévin Redon
ec396bf402 sniff: fix ATR checksum calculation
this issue also cause the sent ATR to be empty

Change-Id: I6edff7aeb3185c835656acde75886fb6c90c0582
2018-07-28 20:59:44 +02:00
Kévin Redon
697199676e sniff: ensure the checksum error flag is also printed
the firmware now also use a generic value_string array (as does the
host application)

Change-Id: I861bd8b52e8f2f2a4786bbe1cc834917119dc394
2018-07-28 20:59:41 +02:00
Kévin Redon
8e84f8125c sniff: rename reset hold/release to assert/deassert
this change is to match the nomenclature used in cardem

Change-Id: Ide99e731cad26aec949ad14d54f46fa611a0b7f8
2018-07-26 15:34:08 +02:00
Kévin Redon
d1c6536154 sniff: send ATR over GSMTAP
Change-Id: Id35129883f08002a4a796b56954a128e2b533245
2018-07-26 14:51:15 +02:00
Kévin Redon
352809992c USB: print decoded USB error
In case of error it also ensures the returned value is NULL.
Else a segfault would occur because the caller (e.g. remsim)
continued on with a free handler.

Change-Id: Ie7f20e3eff03acf77eb08283747ca8e032b9b4c8
2018-07-24 09:57:23 +02:00
Kévin Redon
a71a6f48cb I2C: return error after failed write
The previous mechanism of retrying a failed write could become a
infinite blocking loop (until watchdog tiemout).

Also the array size is used to know how much data to write and verify
instead of a constant.

Change-Id: I8d2d090c5f4d1195f4c7eb29b3958a7bb05f56ec
2018-07-24 09:54:18 +02:00
Kévin Redon
57b60d23cf I2C: add wait time after write to let EEPROM write
The Atmel AT24C02 defines a maximum tWR waiting time after a byte
write of 5 ms before a next write.
Enforcing this wait time also fixed the failed verification in qmod,
where it was reading 0xffff instead of the written value.

Change-Id: I42c90b8d0329e425f275067e87d584212a43a90b
2018-07-24 09:49:18 +02:00
Kévin Redon
b60538888f cardem: fix USB message parsing
the msg->l2h pointer was not set but used later on, e.g. in
dispatch_usb_command_cardem, case SIMTRACE_MSGT_DT_CEMU_SET_ATR):
>   case SIMTRACE_MSGT_DT_CEMU_SET_ATR:
>   >   atr = (struct cardemu_usb_msg_set_atr *) msg->l2h;
>   >   card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
l2h is by default 0, thus not pointing to the actual message l2h.
I wonder how cardem worked worked before with this issue though.

Change-Id: Ifbb53dbf478d8dade82251f769e78e1306e77434
2018-07-18 14:06:23 +02:00
Kévin Redon
680bdaba96 cardem: fix typo
Change-Id: Ibeeb01b21a3ccfa74642f13694a20054e920837e
2018-07-18 14:00:57 +02:00
Kévin Redon
f66af0c640 sniff: add checksum verification for ATR and PPS
a checksum error is only signaled in the USB message with the
corresponding flag.

Change-Id: I277868267c3199eea216ab47bdd09fb2fb944b06
2018-07-11 22:33:16 +02:00
Kévin Redon
5f6b8717a4 fix 'ISO_S_IN_ATR not handled' gcc warning
when building the cardem application GCC would output the following warning:
libcommon/source/card_emu.c: In function 'card_emu_process_rx_byte':
libcommon/source/card_emu.c:764:2: warning: enumeration value 'ISO_S_IN_ATR' not handled in switch [-Wswitch]
  switch (ch->state) {
  ^~~~~~

in card emulation the reader should not send data while the card is
sending its ATR.
this is true for other states already handled (RESET, ...). in
these cases an error message is output.
this behaviour is now the default case as data from the reader is
only expected in 3 cases: ISO_S_WAIT_TPDU, ISO_S_IN_TPDU, and
ISO_S_IN_PTS.

Change-Id: Ifbc8dbe1c9f176343304f211c7e6068fb977961e
2018-07-11 22:24:46 +02:00
Kévin Redon
ac0843af83 make adc2uv common
when building the trace app for the simtrace board gcc was outputing
the following error:
libboard/common/source/boardver_adc.c:20:17: warning: 'adc2uv' defined but not used [-Wunused-function]
 static uint32_t adc2uv(uint16_t adc)

adc2uv is used by qmod, and defined in two places:
in boardver_adc.c and mode_cardemu.c.

this change will have adc2uv only defined in boardver_adc.c and make
available in the header to be used by mode_cardemu.c.

Change-Id: I8a772638fa8dd02d8bc8b7631de5af5a22647c55
2018-07-11 22:24:46 +02:00
Kévin Redon
31ed8029b7 host sniff: add functions to print flags
Change-Id: If3c0a4790662bcc64db5ff03adcc033836e16ad0
2018-07-11 22:24:40 +02:00
Kévin Redon
3b7624c120 host sniff: process remaining usb messages in buffer
Change-Id: I1746c0187b2e5dbef44b4b336fee3bd9ded15079
2018-07-11 22:01:58 +02:00
Kévin Redon
f000831d72 sniffer: fix inverted reset meaning
Change-Id: I860e2e29c059e1e0ec126695bb68d489891a17da
2018-07-11 22:01:58 +02:00
Kévin Redon
b37bda0b55 sniffer: only allocate USB message if queue is not too long
When the host does not retrieved the USB messages, they keep getting
queue in the firmware, filling the RAM, and preventing further memory
to be allocated.

Change-Id: I0e447acdf757dcb5dc5c4d8b84a4235866914cad
2018-07-11 22:01:58 +02:00
Kévin Redon
c6b968067d sniffer: also send malformed message over USB
Change-Id: I124c8db1d2f836e185630bbe8b5e52eb085d702a
2018-07-11 22:01:58 +02:00
Kévin Redon
a95bb1e85d minor: fix linker warning
linker warning:
obj/simtrace/dfu_sniffer.o: In function `usb_send_data':
/media/data/work/simtrace2/simtrace2/firmware/libcommon/source/sniffer.c:338: warning: undefined reference to `putchar'

Change-Id: I934f3fcb474d4046e921511a024c3a0b8533c782
2018-07-11 22:01:58 +02:00
Kévin Redon
da5578bd85 sniffer: set LED pattern
The red and green LEDs are now used as follows:
- red on = power (firmware is running)
- red blink = error detected (e.g. during ISO-7816 parsing)
- green on = running (sniffer mode is running)
- green blink = activity (e.g. USB message sent)

Change-Id: Ib1b6ff87fb92d6ed3ecae4bc89386206aaab508e
2018-07-11 22:01:58 +02:00
Kévin Redon
d975411511 LED: add need pattern
new LED pattern: off for 200 ms and then on

Change-Id: Id2c40dc20d75ed6f38b735164ad1eb2860dc480c
2018-07-11 22:01:58 +02:00
Kévin Redon
a2fccba96c sniffer: move reset handling from ISR to main loop
Change-Id: Ia88fb4baf49017524bb201123da3511e5342ba48
2018-07-11 22:01:58 +02:00
Kévin Redon
411428eb5e sniffer: move data print before USB send
when the host software does not retrieve the USB messages the memory
is filled and no new USB messages can be allocated, preventing the
following code to print the message

Change-Id: Ie8946894a84cb853b45555f7abb1ca6f32111425
2018-07-11 22:01:58 +02:00
Kévin Redon
f82f0f6eff USB: add flags for sniff data and centralise transfer
Also fix issue in usb_msg_alloc_hdr and add cosmetic spaces around
operations.

Change-Id: I768a0ad639aa5e648a630af72d01f7b68082b6b6
2018-07-11 22:01:58 +02:00
Kévin Redon
55f0612c8e cosmetic: put spaces around operations
Change-Id: If5ba5f8d16680e8403944274336ea595017063db
2018-07-11 22:01:58 +02:00
Kévin Redon
33d1eb73fd replace leading spaces with tabs
Change-Id: I86783eba0827b58303b10310e9f6b9625e1a27f1
2018-07-11 22:01:58 +02:00
Kévin Redon
93717e43b3 set linux end of line
Change-Id: I5200f0d6f39b0641cac26a4109a3cd33e8474b9b
2018-07-11 22:01:58 +02:00
Kévin Redon
9a12d68c74 firmware: set license to GPLv2+
Change-Id: Id4c00159f984976b6d8641900fb64e36a3a30407
2018-07-11 22:01:58 +02:00
Kévin Redon
efbcf38afb host: set license to GPLv2+
Change-Id: I0948d74874af1d3a0f1b4cbcb4a838e4ecd9fe3f
2018-07-11 22:01:56 +02:00
Kévin Redon
9918c2840e DFU: use central DFU override check
TRACE_INFO will also provide the DFU start reason, but TRACE_INFO
(TRACE_LEVEL >= 4) should only be used for debugging.
WARNING: With TRACE_LEVEL >= 4 the DFU binary is over the maximum of
16 kiB allocated for the DFU bootloader.
Thus make combined will not boot the main application because its
start if after the expecte 16 kiB address; and flashing using DFU
will overwrite the DFU bootloader itself.

Change-Id: I82323e0f76c03f67df7dc8f2b6783166cc25f3aa
2018-07-11 20:48:24 +02:00
Kévin Redon
d24e9bde26 DFU: re-enable UART after testing forced bootloader
The qmod does not have a separate force button as simtrace has.
Instead it check is TX and RX of UART are shorted using PIO.
If the pins are not set back to the UART peripheral, the TRACE/debug
console output will not work anymore.

Change-Id: Id434b49909d6395a2f93a00f39d2d770a5725466
2018-07-07 14:56:50 +02:00
Kévin Redon
2bdaa73aff UART: remove unused code
PutChar already takes care of enabling the IRQ

Change-Id: I63af5eba27c9a6f3e23412060028e817e4d9f233
2018-07-07 14:53:50 +02:00
Kévin Redon
fcf2743552 UART: make IRQ/ISR enabling simpler
Change-Id: Id3742850eb5bac91559e0c2b4144bd7b1ae5b07b
2018-07-07 14:51:35 +02:00
Kévin Redon
d44cb80bc5 DFU: disable configured console UART before starting main app
The DFU uses the UART peripheral (with IRQ/ISR) for the debug output
console. Before starting the main application we should make sure
this configuration is reset to avoid interference (particularly the
IRQ/ISR).
This is not too important though since the main application
reconfigures the UART for console output.
Other peripheral could also be disabled (e.g. all other PIO used
by DFU), but most of them also get configured by the main application.

Change-Id: I8234d1b85938ad6393094c08183f613ad09ee01b
2018-07-07 14:43:50 +02:00
Kévin Redon
9e29a3eb37 DFU: set stack pointer before starting main app
The stack size is fixed. The linker script puts the stack section
after the bss section. The initial stack pointer is not at the
end of the RAM (as often seen).
Thus the initial stack pointer address of the main application
is different than the one from DFU. When starting the main
application the stack pointer needs to be set to the new value.
If this is not done the main application stack may overwrite the
data in bss, even without exceeding the fixed stack size.

Change-Id: Ie354d603fe302d3d5bdfa9c31575411de722323b
2018-07-07 14:18:58 +02:00
Kévin Redon
bf6b1b1a3e buffer: increase buffer size to 512 to cope with fast and long TPDUs
Change-Id: I194c90cf09306a982d80c5bf1222397af6e658a9
2018-07-04 17:55:20 +02:00
King Kévin
4cbdc7cf18 fix LED switching on/off
In the SIMtrace and QMOD schematics the LEDs are connected to +3.3V.
Thus to switch the LED on we need to set the pin low.

Change-Id: Id8cc27e6f0b6556ba5e7ea4d254dd0fe59042a0c
2018-07-04 17:55:20 +02:00
King Kévin
86f48fc962 minor style change: use ARRAY_SIZE
Change-Id: Ia5243c342535963a3800849cd5a7d183a510d2d6
2018-07-04 17:55:20 +02:00
King Kévin
1200a5228f sniffer: add waiting time WT update
the waiting time (WT) is used to detect timeouts (e.g. for
unresponsive card or just to signal an error/NAK). it is essential
to detect to timeout to end current data transfer (e.g. change state).
by default (after a reset) to timeout is 9600 ETU, but this can change
at two places:
- after the ATR using the value of TC2 (if present)
- after a PPS (only F is used, and not D)

because the timeout value can be larger than the 16-bit of the USART
TO register, an external variable needs to be used for the count down.

Change-Id: I9735660ffce161cec8d4e63fa60a66fc8ef57525
2018-07-04 17:55:20 +02:00
Kévin Redon
fe763b7698 sniffing: decrease USB IRQ prioprity to prevent USART overrun
Handling the USB message queue is done in an ISR and take quite some time.
This can cause a USART/SIM sniffing buffer overrun, resulting in data loss.
By setting the USB IRQ lower than the USART IRQ, the USB ISR can be
interrupted (for short) and no data gets lost.

Change-Id: I870a0aa8e251bbb53249c54bfcaa45de5b5a9486
2018-07-04 17:55:20 +02:00
Kévin Redon
c9bd715289 sniffing: fix procedure byte handling and make TPDU parsing more strict
Change-Id: If991152f11c4b864ab1386f21dc13c335e6b281f
2018-07-04 17:55:20 +02:00
Kévin Redon
35e8bdf879 sniffer: also send incomplete (e.g. timeout) data (PPS/ATR/TPDU)
Change-Id: Ib070aca181042b477f1ffec48d63dc56c1e4609a
2018-07-04 17:55:20 +02:00
Kévin Redon
709a431ab9 sniffing: move conversion convertion and flag processing from ISR to main loop to keep ISR fast and focus on data capture
Change-Id: Ieefa8a5f81dbcc12c1ad3059660dbffa0c1a4961
2018-07-04 17:55:20 +02:00
Kévin Redon
30f90a78fc console: drop data to be send when buffer is already full
don't wait for space to be available in the buffer since since would
prevent from processing non-console (e.g. debug) more important data

Change-Id: Ia625b09eb30bb7b43edd3989f697d8ef33200f28
2018-07-04 17:10:08 +02:00
Kévin Redon
7406337a7f sniffer: display F and D values frim PPS
Change-Id: I3641dcb6c24695a6d3dd3a1ee4333f56a07c99f0
2018-07-04 17:10:08 +02:00
Kévin Redon
6e3f1121e6 host USB: add host application to receive and display USB sniffing messages sent by firmware
Change-Id: Idefbf21e0bbd2a1e3647fe9aebaf88d1b62dae2d
2018-07-04 17:10:08 +02:00
Kévin Redon
de97fd25bd sniffer USB: implement USB communication and send parsed messages
Change-Id: Ice7817480705f2124b08c1ff9a8826558b6d8b2b
2018-07-04 17:10:08 +02:00
Kévin Redon
012940f48e USB device: add USB message structure for sniffer communication
Change-Id: Id2c6f32ade2fec9b9ef91bd8c5e1fd195f2d7351
2018-07-04 17:10:08 +02:00
Kévin Redon
e2f84f6a8b host USB: use central SIMtrace USB ID definition header
Change-Id: Id18e64fba0a2c308a8aef7d3865200bf0237cae9
2018-07-04 17:10:08 +02:00
Kévin Redon
4d6a4b949c host usb_util fix: used provided class, sub-class, and interfave when finding matching interfaces
Change-Id: Ibc06e751e6ca0f9e9a40d82c4eeddfb975240f91
2018-07-04 17:10:08 +02:00
Kévin Redon
a1012b170a USB: add central file to define USB IDs, classes, and endpoints
Change-Id: Iba81f32a92c68a973e8e7adbc4c2a1064ba5290f
2018-07-04 17:10:06 +02:00
Kévin Redon
42bd026416 minor: fix typos in comment
Change-Id: I01b49e047a586dff449d4e134751108e391a8822
2018-07-04 16:33:00 +02:00
Kévin Redon
638cec820f sniff: add WT timeout detection using USART timeout (TC is not required)
Change-Id: I4ec6e812e7e1eb91005027d2e864fc315550d79c
2018-07-04 16:33:00 +02:00
Kévin Redon
00ec89d73f sniff: add TPDU parsing (TPDUs become APDUs on the upper layer)
Change-Id: I09d050d95bd2ab140fe6b4926a37278eb08cc347
2018-07-04 16:33:00 +02:00
Kévin Redon
cf59919494 sniff: print parsed ATR and PPS; use red LED to show main application is running; use green LED to indicate activity (message parsed)
Change-Id: I8e906bdbf2c91e608757ae442dfb241f981b8f1e
2018-07-04 16:33:00 +02:00
Kévin Redon
11914d9658 LED: add short LED pulse blinking pattern
Change-Id: I0fdc2f902a3b92da6aa9b9c8500abae8a2f79447
2018-07-04 16:32:54 +02:00
Kévin Redon
3113e3d2e5 update_fidi: remove debug output since this function is called in time critical ISR
Change-Id: I08f407d407a18dae3f360ddc64769ddfaeb5b559
2018-07-04 14:29:28 +02:00
Kévin Redon
9def7631ba DFU: switch green LED on to indicate DFU mode, and red LED to indicate flashing activity
Change-Id: I8e34fd869ed94ad122d6a17f5a432f5a09b820bb
2018-07-04 14:29:28 +02:00
Kévin Redon
ca9e4bf4ba board: fix LED pin definition
Change-Id: Ia6c80c0268dec708845e1dad281caaa42027f9db
2018-07-04 14:29:28 +02:00
Kévin Redon
8210ec3f62 DFU: remove force bootloader button debug message since the console is output message is not initialized yet
Change-Id: Ibea0105929a8dc38b43dacd9d1e576d7b51d0c6a
2018-07-04 14:29:28 +02:00
Kévin Redon
8fa6ff5979 sniffer: use ISR to store sniffed data in buffer, add ATR and PPS parsing, and PPS related FiDi update
Change-Id: I4b38ce1d80e370fda6aa181e959ba3f1286bb922
2018-07-04 14:29:28 +02:00
Kévin Redon
866d20b10e trace: increase watchdog for 500 to 2000 ms to provide more time handling buffered data
Change-Id: Iacd85525f05e692b44183bd4c4585b9e70865cfe
2018-07-04 14:29:28 +02:00
Kévin Redon
4fe99fad59 ISO7816: change update_fidi to use provided USART
Also disables write protection for USART register if required

Change-Id: I716f4bc3a22800cbce402b146f14ef8b2aab2a98
2018-07-04 14:29:28 +02:00
Kévin Redon
7be52ec1ce SIMtrace: enable interrupt on edge dection for SIM_RST pin to reset the sniffer ISO state
Change-Id: I92ff29abd6a8690dd033d8cf13ad0d1ff9740fe5
2018-07-04 14:29:28 +02:00
Kévin Redon
a2b367633c SIMtrace: fix default SIM_RST pin state to allow phone controlled reset
Change-Id: I1942ec6bd499cb2e14f6d7699a2b2d9b4197e654
2018-07-04 14:29:28 +02:00
Kévin Redon
927ffb46eb SIMtrace: only enable main sniffing mode on SIMtrace board
Change-Id: Iff6ebb1d98aa0c31f6d78508afde8f1b05f0f85b
2018-07-04 14:29:28 +02:00
Kévin Redon
d7a6de57d2 sniffer: add state definitions, improve IRQ handling, update pins configuration
Change-Id: I6b5dfd6d573ac122a60585a24c8a620642805ad5
2018-07-04 14:29:27 +02:00
Kévin Redon
353351ddf4 simtrace: add support for sniffing on both USART
Change-Id: I69eb458e7cb186c990e5d6fbc780f37fdd0cd884
2018-07-04 14:28:19 +02:00
Kévin Redon
4091d78c4b board: comment USART definitions and add corresponding IRQ numbers
Change-Id: I3c38e7d75bc7b511827c33af69e335e50d0b35d2
2018-07-04 14:28:19 +02:00
Kévin Redon
ee62a9da56 simtrace: add dedicated power pins configuration for sniffing
Change-Id: Ie37edbae6ea42d2b0c2a30eb5590afd0be797d39
2018-07-04 14:28:17 +02:00
Kévin Redon
45ad62d8d4 sniff: use USART 0 instead of USART 1
Use USART 0 connected to the SIM card side to sniff the communication.
The card side can also measure ETU times.
Do proper pin initialization.
This code can already capture the ATR communication between phone and card.

Change-Id: I0597ec723cb2225540c89c3821b91d8a45adfcd6
2018-07-04 11:24:13 +00:00
Kévin Redon
2c4e2af21f SIMtrace board: comment and fix pin definition
Change-Id: Ic77ad5bf6c00c9122c6bb0e12b90e6c5406855fd
2018-07-04 11:24:13 +00:00
Kévin Redon
7b73462442 sniff mode: handle USART 1 RX interrupt to show sniffer data
Change-Id: I5504369aed39844b7cf21e5b3ccb542daa6b946e
2018-07-04 11:24:13 +00:00
Kévin Redon
36abece0b1 enable (empty) sniffer support for SIMtrace board
Change-Id: I51619135fd6f5423542f261e7d76bab1a5713e2b
2018-07-04 11:24:13 +00:00
Kévin Redon
f9997e9d26 copy working cardem app to trace
because the applications share the board capabilities defined in
libboard/*/include/board.h and USB configurations are enabled according
to the previously defined capabilities in libcommon/source.usb.c, all
applications actually offer the same functions.
thus creating the trace application is only mainly a cosmetic change, as the
sniffer function will also be present and enabled in the cardem application.

Change-Id: I24b3500a0905cbd622507722280b3c7e7f188bde
2018-07-04 11:24:13 +00:00
Harald Welte
05cc7f6531 ringbuffer: Don't print/TRAC from ringbuffer
In commit eac1bec428 we start to use the
ringbuffer inside the console printing code.  As a result, we must not
use TRACE_*() or printf() from within ringbuffer.c code to avoid
infinite recursion.

Instead, let rbuf_write() return a negative return value in case the
ring buffer overflows.  This way, the callers (outside the
console/stdout code) can print an error message themselves.

Change-Id: Ib009f013be119dbad22fa2b7d60ec8dee59baee5
2018-07-04 04:42:22 +02:00
Harald Welte
46893451de echo all command characters entered on serial console
This is required to make python pexpect.fdexpect happy, as it
requires that all characters are echo-ed back in order to detect
when the output of a given command starts.

Change-Id: I73b24e43f6c8b86a2766aba67d8307c184448aa0
2018-07-03 22:30:30 +02:00
Harald Welte
cb6e20596e contrib/jenkins.sh: Also run firmware tests + build-test host software
Change-Id: Ie53857164d0a21daac334057c5bafbfd9912bf4b
2018-07-01 16:33:25 +02:00
Harald Welte
bb2eb19fb1 firmware/test: Add more include paths
Change-Id: I4287fbae6921ed0605265812df5d7243e8857864
2018-07-01 08:47:39 +02:00
Harald Welte
9d90d284ed Use system include <foo.h> notation for libosmocore headers
the curent local copies of libosmocore headers + source is a temporary
hack anyway. We should instead rely on a system-wide install of
libosmocore cross-compiled for arm-none-eabi.  But leave that as a
second (later) step beyond this patch.

Change-Id: Ia63fd842d45a2b404233b4326050e7eda0604cf0
2018-06-29 22:26:57 +02:00
Harald Welte
ebe8b2069c Makefile: fix automatic creation of obj directory
since we're using obj/$BOARD, we must use "-p" to create the directory
recursively
2018-06-29 21:44:12 +02:00
Harald Welte
105c1dce4f add contrib/jenkins.sh for build verification
The contrib/jenkins.sh script will build all supported apps for all
supported builds.  It will be used by jenkins/gerrit build testing.
2018-06-29 21:39:42 +02:00
Harald Welte
1cfc2614dd apps/dfu/main.c: Avoid variable declaration in for loop initial
This fixes the following compile error:

apps/dfu/main.c:73:3: error: 'for' loop initial declarations are only allowed in C99 or C11 mode
   for (unsigned int i=0; i<len; i++) {
   ^
apps/dfu/main.c:73:3: note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your code

which was recently introduced in b73f0a00bc
2018-06-29 21:07:41 +02:00
Kévin Redon
a9bca48914 ring buffer: increase buffer size from 128 to 256 to cope with large debug output 2018-06-29 20:07:31 +02:00
Kévin Redon
eac1bec428 console: use buffer and interrupts instead of busy loops for UART debug output 2018-06-29 20:07:31 +02:00
Kévin Redon
51c128bc35 DFU: fix typo in USB strings 2018-06-29 20:07:31 +02:00
Kévin Redon
869dbfafe4 DFU: incread watchdog timeout and restart watchdog before writing in flash to prevent the watchdog to trigger while flashing 2018-06-29 20:07:31 +02:00
Kévin Redon
80303c135b DFU: only boot the application if it has a valid start 2018-06-29 20:07:31 +02:00
Kévin Redon
d86cab0080 DFU: uncomment print message when DFU is forced using the button 2018-06-29 20:07:31 +02:00
Kévin Redon
b73f0a00bc DFU: unlock the flash before writing, verify written data, and relock it 2018-06-29 20:07:31 +02:00
Kévin Redon
f5869d4a59 USB: implement USB reset by setting the on-board pull-up on D+ low 2018-06-29 20:07:31 +02:00
Kévin Redon
4136c242a8 USBD: send empty packet when non-existing descriptor string is requested
Sometimes descriptor string 0xee is requested.
This is a mechanism used by Microsoft Windows to further identify the USB device.
Instead of stalling, as is the original code, leading to an USB reset, we send an empty packet.
I am not sure if sending an empty string would be better, but an empty packet seems sufficient.
2018-06-29 20:07:31 +02:00
Kévin Redon
318309f30f dfu: fix address destination check and add stack overwrite check in USBDFU_handle_dnload
During DFU download the destination start address is checked to not exceed the
RAM or flash end address, but it is also necessary to check if the end of the
data to be downloaded is also within the allowed range.
When downloading to RAM it is also necessary to check if the data to be
downloaded does not overwrite (i.e. corrupt) the stack.
2018-06-29 20:07:31 +02:00
Kévin Redon
0828b914e7 README: rewrite to better explain environment variables and point to the wiki for flashing 2018-06-29 20:07:31 +02:00
Kévin Redon
76be7c806e fix pointer casting warning
fixes following warning:
libboard/common/source/board_cstartup_gnu.c:137:11: warning: assignment to 'void (*)(void)' from 'unsigned int' makes pointer from integer without a cast [-Wint-conversion]
  appReset = pSrc[1];
2018-06-29 20:07:31 +02:00
Kévin Redon
a38a126361 fix: initialize uninitialized variable in USBDFU_DFU_RequestHandler 2018-06-29 20:07:31 +02:00
Kévin Redon
6822716428 add printf attribute declaration to remove warning
the __attribute__ ((format (printf, 1, 0))) declaration remove the following
compilation warning:
warning: function 'osmo_panic' might be a candidate for 'gnu_printf' format
 attribute [-Wsuggest-attribute=format]
   osmo_panic_default(fmt, args);
2018-05-21 17:18:58 +02:00
Kévin Redon
a93f7273b3 fix: remove duplicate volatile declaration 2018-05-21 17:17:20 +02:00
Kévin Redon
432ba5140e add copyright notice
The original board startup script is provided by Atmel.
It has been modified to handle application or DFU booting.
The copyright notice has been updated to reflect this change.
2018-05-21 17:13:50 +02:00
Harald Welte
849d20e29e Add firmware/TODO.txt that was not committed so far 2018-05-11 15:49:31 +02:00
Harald Welte
e48d6f2321 Add README.md 2018-05-11 15:48:54 +02:00
Harald Welte
af616ec4e2 CCID driver: Use USBD_GetDriver() instead of non-initialized state variable 2017-11-29 00:45:23 +01:00
Harald Welte
6051e126da CCID: re-enable control request handler for CCID class requests 2017-11-29 00:26:34 +01:00
Harald Welte
7f62c24532 USB: Handle DFU requests by USBD.c to keep application callback
e.g. in CCID mode we need to treat class-specific control requests,
and we want to do this in a way how the CCID code doesn't need to
understand about DFU.
2017-11-29 00:24:28 +01:00
Harald Welte
75cf93e04d rename ccid.c to mode_ccid.c to align with mode_cardemu.c 2017-11-28 23:00:40 +01:00
Harald Welte
2afd57f00a cardem: Don't dispatch UART IRQs to possible NULL pointers
A given configuration might not expose callback functions for
the UART interrupts.
2017-11-28 22:52:56 +01:00
Harald Welte
0633b25974 iso7816_4: Re-trigger watchdog while waiting for character 2017-11-28 22:47:09 +01:00
Harald Welte
c1e2254854 simtrace: Boot into DFU when BOOTLOADER button is pressed
This recovers the old functionality of the SAM7 based OpenPCD firmware.
2017-11-28 22:29:53 +01:00
Harald Welte
27f5fc681c DFU: Move "Override DFU" (force DFU) code to board-specific section
Each board can define its own conditions on which the controller should
boot into DFU mode rather than normal application mode.  Let's move the
"UART loopback jumper" to QMOD specific part.  For SIMtrace we have an
actual button and can use that in a future patch.
2017-11-28 22:15:56 +01:00
Harald Welte
7b250bfc8d board_simtrace: Add minimal debug menu on debug USART 2017-11-28 22:10:49 +01:00
Harald Welte
ed75c62acf {ccid,sniffer}.c: Add comments on USB callbacks 2017-11-28 21:23:12 +01:00
Harald Welte
5c081911a9 remove dead code (source/phone.c), superseded by card_emu.c/mode_cardemu.c 2017-11-28 21:21:50 +01:00
Harald Welte
5e6e8dcbde Make build of CCID code succeed again on BOARD=simtrace 2017-11-28 20:58:06 +01:00
Harald Welte
c35998e20d Makefile: Disable -Wundef and -Wsign-compare for now
This silences tons of warnings which are making it hard to identify
actual issues when looking at the compiler output.
2017-11-28 20:47:23 +01:00
Harald Welte
ba2ad563cc fix build of APP=cardem on BOARD=simtrace 2017-11-28 19:49:41 +01:00
Harald Welte
fc87c24326 mode_cardem: Build on platforms without WWAN_PERST suppotrt 2017-11-28 19:17:27 +01:00
Harald Welte
f231541601 Fix typos in usb.c, llist_irqsafe.h and dfu.h 2017-11-28 19:16:57 +01:00
Harald Welte
119624f46f WIP: use local_irq_{save,restore}() 2017-11-04 12:28:30 +01:00
Harald Welte
7b36306113 [firmware] WIP: make talloc irq-safe 2017-11-04 12:17:09 +01:00
Harald Welte
eb50c9f914 [firmware] sim_switch + wwan_perst: Don't re-initialize
The logic to detect if the respective module is already initialized
or not was broken.  When performing initialization, we of course need
to set initialized=1.
2017-11-03 20:52:35 +01:00
Harald Welte
965d5c918a [firmware] cardemu: Skip CARD_INSERT if board doesn't support it 2017-11-03 20:48:11 +01:00
Harald Welte
514c6d1da0 [firmware] wwan_perst: Print index when releasing WWAN_PERST 2017-11-03 20:40:56 +01:00
Harald Welte
e7f2f9a5e0 [firmware] wwam_led: use 0/1 instead of 1/2
most (all) other code modules have already moved over to
consistently using a 0-based index.
2017-11-03 20:38:31 +01:00
Harald Welte
4e837d45db [firmware] card_pres: use modem number at start of line
... like most other code modules, too
2017-11-03 20:36:17 +01:00
Harald Welte
b52b886186 [firmware] card_pres: Use 0/1 index number instead of 1/2
We have moved most (all?) other code to work with slots 0/1
rather than 1/2.
2017-11-03 20:33:10 +01:00
Harald Welte
c47fc5febf set local slot LED according to remote/local state.
The LED is illuminated as long as the slot is in local (physical SIM
card) mode.
2017-05-20 14:46:57 +01:00
Harald Welte
02d0ec6e08 uart_console: Re-start watchdog during busy-waiting for serial chars 2017-05-20 14:46:57 +01:00
Harald Welte
3b646955b9 Fix swapped manufacturer/product strings
the */usb_strings.txt files always assumed that the first line is the
manufacturer string, followed by the product string in the second line.

However, the enum strDescNum had it the other way around. Let's fix it
by adjusting the enum to reality.

Fixes: SYS#3591
2017-05-14 23:15:11 +02:00
Harald Welte
a601635885 host: Allow matching of device to USB path, not just address
USB addresses change every time the device re-enumerates, while the path
reflects the physical topology of USB connections and stays persistent
unless the usb cabling is changed.  Let's allow the user to specify the
path instead of the address to uniquely identify a given slot.
2017-05-11 01:31:45 +02:00
Harald Welte
37ad41e092 host: Ignore some more libusb error return codes
It seems that sometimes we get even an LIBUSB_ERROR_IO and failing on
errors breaks the application, while ignoring it works.  Not sure why
that really is, but for now it increases reliability.
2017-05-11 01:13:58 +02:00
Harald Welte
66de830f55 host: Switch SIM to remote and issue modem reset on startup
as soon as simtrace2-remotesim is started, we issue the command to
instruct the use of the remote SIM card and ask the modem to reset
itself (to start using the new remote sim).
2017-05-11 01:13:04 +02:00
Harald Welte
23c00b6ad3 cardemu: Fix interpretation of MSGC_MODEM messages
msg->l2h should always point at the first byte of the header after the
generic simtrace header.  For some reason this doesn't work if used
globally, but it is required for the MSGC_MODEM messages to be
interpreted correctly.
2017-05-11 01:11:43 +02:00
Harald Welte
253991789a dfu: make sure to not bloat the loader with main board init stuff. 2017-05-11 00:47:29 +02:00
Harald Welte
0709d2d842 perst/sim_switch: Log events using TRACE_INFO 2017-05-11 00:06:00 +02:00
Harald Welte
44622dfd8d consistently use 0-based counting of modems/slots 2017-05-11 00:04:50 +02:00
Harald Welte
b91f6ad848 firmware: fix various compiler warnings 2017-05-10 23:20:50 +02:00
Harald Welte
9f38dddfcc host: fix various compiler warnings 2017-05-10 23:20:50 +02:00
Harald Welte
d03960525e host: Split transport from slot
In current implementations, we have one interface (with it's own
separate set of USB end-points) per slot.  However, the USB protocol
already includes a slot-number in the header to be able to remove that
restriction in future versions.

Also, if the USB protocol is used remotely over a network, then we could
multiplex differnt slots from different USB interfaces into one stream
on the network side.

In order to prepare the data structures in the host program, let's
introduce that logical split there, too.  Might seem a bit like
overkill, but I don't want to rewrite all code later...
2017-05-10 23:20:46 +02:00
Harald Welte
08b77ba9ee host: split the transport layer from card emulation
We want to be able to use some code irrespective of the application
(emulation, tracing, ...), so let's split the transport struct out of
the cardem_instance.
2017-05-09 15:11:53 +02:00
Harald Welte
296c401275 host: cosmetic cleanup, function renaming 2017-05-09 15:02:52 +02:00
Harald Welte
5c583d3535 Generalize SIM switching code and allow local/remote switching via USB 2017-05-09 13:24:28 +02:00
Harald Welte
114e74d322 wwan_perst: Warn if somebody failed to initialize us 2017-05-09 13:24:28 +02:00
Harald Welte
2e9254ac3f cardem: Implement WWAN Modem reset via USB
Using the SIMTRACE_MSGT_DT_MODEM_RESET message
2017-05-09 13:24:28 +02:00
Harald Welte
cb093ce878 wwan_perst: Support varying timeout and permanent active/inactive 2017-05-09 13:24:28 +02:00
Harald Welte
25a9a80ff5 Convert to new generalized SIMTRACE2 USB protocol
The current protocol was card-emulation specific.  The new protocol is
generic/flexible enough to accommodate both tracing and card emulation,
as well as modem control and other future extensions.
2017-05-09 13:24:23 +02:00
Harald Welte
ed1efc5035 qmod: debug_cmd: Avoid 'Unknown command' for valid commands 2017-05-07 23:10:02 +02:00
Harald Welte
f8c83a4d64 Make hardfault handler a bit more verbose 2017-05-07 23:10:02 +02:00
Harald Welte
28174982b6 qmod: Initialize ST12 specific I/O pins only on ST12 2017-05-07 23:10:02 +02:00
Harald Welte
8e7fca3255 migrate from req_ctx to msgb
We now generalize the USB communiction and abandon the 'req_ctx'
structure inherited from openpcd.  Instead we use the libosmocore 'msgb'
structure to handle incoming and outgoing USB tranfers.  We also use
linuxlist-based msgb-queues for each endpoint.
2017-05-07 23:09:56 +02:00
Harald Welte
eb81d23a56 import libosmocore msgb handling (and dependencies)
This is supposed to be replaced with upstream libosmocore, as soon as
that has a proper maintained embedded build (again).
2017-05-07 13:18:36 +02:00
Harald Welte
0380d74405 Makefile: remove .p files during 'make clean' 2017-05-07 11:20:40 +02:00
Harald Welte
9457bf765d Makefile: Don't warn about failed inlines 2017-05-07 11:20:24 +02:00
Harald Welte
9ac794c770 Add llist_add_irqsafe() similar to llist_add_tail_irqsafe() 2017-05-07 11:19:45 +02:00
Harald Welte
41eb98b78d board_gpio.gnumeric: Update to QMOD v3 (SIMPRES1/SIMPRES2) 2017-05-05 23:17:31 +02:00
Harald Welte
caca0b1e7a Makefile: Add new 'combined' target to build combined DFU+APP image 2017-05-05 23:17:31 +02:00
Harald Welte
6d1128e9d1 QMOD: Add code to determine SIM Card presence 2017-05-05 23:17:27 +02:00
Harald Welte
7e4390f181 qmod: wwan_led.c: Fix handling of LED for second Modem 2017-05-05 20:58:53 +02:00
Harald Welte
9164a6d335 qmod: Disable various console commands on ST34
A number of commands related to the USB hub and the EEPROM are only
available on ST12, but not on ST34.  Let's remove them if not
applicable.
2017-05-05 20:58:52 +02:00
Harald Welte
2cbc9b29f3 use same USB Product ID for DFU and runtime mode
This was introduced for interoperability with operating systems that
might prefer such setup (I heard that Windows prefers this about a
decade ago, but I don't have any personal experience with it).

However, using different VID/PID between DFU and RT breaks usability of
dfu-util, and I really think this matters much more to our users and
developers.
2017-05-05 00:34:28 +02:00
Harald Welte
8196e4d1be remove old python userspace code
the USB protocol is changing fundamentally anyway, and APDU handling for
card emulation is inside the device, so the old code is incompatible
anyway.
2017-03-08 15:34:23 +01:00
Harald Welte
601e0d3e35 update + split README into general and firmware-specific part 2017-03-08 15:33:33 +01:00
Harald Welte
3d4869cbb4 add missing usbstring.c 2017-03-07 15:51:49 +01:00
Harald Welte
353330dcc7 qmod: Fix polarity of SPDT switch
the default boot state should be to use the local SIM, until the user
changes it (currently only possible via entering '!' or '@' on the
serial console).  The code so far had this completely inverted.
2017-03-07 08:17:19 +01:00
Harald Welte
3bbaba0090 DFU: Disable LED blinking code
Something odd is happening that breaks DFU mode if we blink.  Let's
remove this feature for now.
2017-03-06 22:47:06 +01:00
Harald Welte
e8869fb8ff DFU: Resolve DFU runtime descriptor dynamically from descriptors
We cannoy simply use the DFU runtime descriptor of the DFU mode, but we
have to use the descriptor of the specific currently-selected runtime
configuration.  Let's iterate over the descriptors of a configuration
and find the DFU runtime descriptor in it.
2017-03-06 22:44:42 +01:00
Harald Welte
5b108d8cf0 DFU: initialize g_dfu during real power up
At power-up we need to initialize g_dfu once, to ensure a consistent
state.  Afterwards we want to keep it across (software) reset, but on
power-up the memory would otherwise be filled with random data, causing
issues with detection of DFU/Runtime switching.
2017-03-06 21:51:55 +01:00
Harald Welte
96065cacd7 add simtrace2-list to .gitignore 2017-03-06 21:05:44 +01:00
Harald Welte
1892fc1d7c add udev rules for all (currently) supported devices 2017-03-06 21:03:41 +01:00
Harald Welte
822d66ef69 simtrace2-remsim: Improve support for many interfaces + devices
Rather than using the first available interface on the first available
device, we now have a "simtrace2-list" program that lists all compatible
interfaces on all configurations of all devices on the system
2017-03-06 21:03:31 +01:00
Harald Welte
62bfd8a7a9 simtrace2-remsim: Document and add longopts for UDP forwarding 2017-03-06 20:56:14 +01:00
Harald Welte
b170ea90d3 host: fix some compiler warnings (now that we have -Wall) 2017-03-06 18:59:41 +01:00
Harald Welte
dea64cb746 host: Add "-Wall -g" CFLAGS to get compiler warnings 2017-03-06 18:57:08 +01:00
Harald Welte
2ba03bb9fc simtrace2-remsim: Move away from global variables
When we want to run multiple instances of the card-emulator (e.g. for
multi-modem/multi-card versions of the hardware), the code shouldn't be
using any global variables but have them per-instance.
2017-03-06 18:57:01 +01:00
Harald Welte
abba8a8d85 LED: Introduce LED blinking pattern code
It might be useful to display some different blinking patterns to
indicate specific system state (such as DFU mode vs. regular firmware)
2017-03-06 16:58:00 +01:00
Harald Welte
054216d94d usb: Use different SubClass values for card-emulation and sniffer
This way, host code can dynamically detect which interface supports
which functionality.

The related #defines should be moved to a header file that's shared with
the host application code.
2017-03-06 10:07:17 +01:00
Harald Welte
eab7e456fe USB: Don't specify Class/Subclass 0xff at device level
Actually, at device level we want to specify 0, so we can select
individual Class/Subclass values at Interface values.

Table 9-8 of the USB2 Specification is quite clear about this.
2017-03-06 10:04:56 +01:00
Harald Welte
495a67da7d usb: consistently use named structure initializers 2017-03-06 09:55:37 +01:00
Harald Welte
912b183b29 qmod: Use different Interface Strings for Modem1+2 / Modem 3+4
This makes it obvious in 'lsusb' and to other software on the USB host
which interface is for which of the modems.
2017-03-06 09:28:13 +01:00
Harald Welte
809e5840f9 qmod: Add code to switch between physical and virtual SIM 2017-03-06 09:16:40 +01:00
Harald Welte
0a8306ec69 add gnumeric spreadsheet with GPIO/Pin assignments of all boards
This software is supposed to support a SIMTRACE1 with SAM#, as well
ast the OWHW and QMOD hardware.  Let's compare the GPIO/Pin assignments
of the SAM3 in one shared spreadsheet.
2017-03-05 22:17:28 +01:00
Harald Welte
2bff7cd9c2 tc_etu: Don't confiugre unused TIOA pin of TC0 + TC2
When initializing the TC blocks, let's only configure the GPIO pins TCLK
and TIOB, and not the unused TIOA pin.  That pin is actually used for
(separate) different functions in both qmod and owhw.
2017-03-05 22:15:54 +01:00
Harald Welte
705e899e5f qmod: (re)activate USB port remapping.
The port mapping is now as follows:

* port 1: ST12
* port 2: modem 1
* port 3: modem 2
* port 4: ST34
* port 5: modem 3
* port 6: modem 4
* port 7: daisy-chaining port
2017-03-05 17:10:26 +01:00
Harald Welte
0e2959859a qmod: Replace hand-crafted delay loop with call to mdelay() 2017-03-05 16:48:47 +01:00
Harald Welte
c6e482d581 qmod eeprom/i2c: Re-start watchdog while slow bit-banging 2017-03-05 16:24:29 +01:00
Harald Welte
1776997f8a remove old 'notes' file with german textaul notes 2017-03-05 13:30:32 +01:00
Harald Welte
596e666fa0 fix symlink that caused host programs to not build 2017-03-05 13:28:32 +01:00
Harald Welte
2363fa0327 Generate USB Strings from apps/*/usb_strings.txt files at compile time
This way we can skip the manually-crafted USB string definitions in the
dfu_desc.c and usb.c files.
2017-03-05 10:16:25 +01:00
Harald Welte
1405100dff DFU: Introduce board/app-specific override for booting in DFU mode
Using the USBDFU_OverrideEnterDFU() function, a board/application can
define extra conditions when the system should boot in DFU mode, even if
it was not explicitly switched to DFU mode from the application.

The app/dfu/main.c uses this mechanism to boot into DFU mode if the
stack + reset vector addresses are not plausible (i.e. some random junk
appears to be flashed in the application partition) or if the user
places a jumper accross the RxD+TxD lines of the debug UART.  The idea
is that the system can be recovered by placing this jumper and then
re-installing the application from DFU.
2017-03-04 19:17:27 +01:00
Harald Welte
7214b4747f Make sure to print CPU Reset Cause when starting the software 2017-03-03 19:02:09 +01:00
Harald Welte
45ebe4591a Enable Watchdog (500ms) 2017-03-03 19:01:53 +01:00
Harald Welte
aaba4af46c Use Supply Controller to avoid running SAM3 on voltages lower than 3.0V
Sometimes there is some leakage current via some I/O that's sufficient
to power up the  SAM3S.  Use the supply monitor to make sure the CPU
will be reset (and kept in reset) if the supply voltage is below 3.0V.
2017-03-03 18:48:13 +01:00
Harald Welte
3ecbf678db only simtrace is bus-powered, SAM3 on qmod + owhw are self-powered 2017-03-03 02:10:34 +01:00
Harald Welte
8adf0ac2ce DFU app: call into board_main_top() for qmod related initialization 2017-03-03 01:52:34 +01:00
Harald Welte
f415d7163b Call USBD_Disconnect before software-triggered CPU reset
This makes sure that we'll re-enumerate on the USB, as a CPU reset
apparently doesn't automatically release the pull-up and notify the hub
that we were gone?
2017-03-03 01:51:43 +01:00
Harald Welte
ec0837c463 change from \r\n (CRLF) to \n\r (LFCR)
For some strange reason my output is garbled in both the 'screen' and
'cu' teerminal programs and 'raw' terminal (stty) mode.  I fail to
understand why, but let's simply adjust the code as needed for now.
2017-03-03 01:33:24 +01:00
161 changed files with 18661 additions and 10979 deletions

2
.gitignore vendored
View File

@@ -17,5 +17,7 @@ tags
*.size *.size
*.bin *.bin
*.p *.p
host/simtrace2-list
host/simtrace2-remsim host/simtrace2-remsim
host/simtrace2-remsim-usb2udp host/simtrace2-remsim-usb2udp
usb_strings_generated.h

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "usb_application/pysim"]
path = usb_application/pysim
url = git://git.osmocom.org/pysim

27
Makefile Normal file
View File

@@ -0,0 +1,27 @@
all: fw utils
define RULES
fw-$(1)-$(2):
make -C firmware BOARD=$(1) APP=$(2)
fw-$(1)-$(2)-clean:
make -C firmware BOARD=$(1) APP=$(2) clean
endef
$(eval $(call RULES,simtrace,dfu))
$(eval $(call RULES,simtrace,trace))
$(eval $(call RULES,simtrace,cardem))
$(eval $(call RULES,qmod,dfu))
$(eval $(call RULES,qmod,cardem))
fw-clean: fw-simtrace-dfu-clean fw-simtrace-trace-clean fw-simtrace-cardem-clean fw-qmod-dfu-clean fw-qmod-cardem-clean
fw: fw-simtrace-dfu fw-simtrace-trace fw-simtrace-cardem fw-qmod-dfu fw-qmod-cardem
utils:
make -C host
clean: fw-clean
make -C host clean
install:
make -C firmware install
make -C host install

131
README.md
View File

@@ -1,112 +1,39 @@
# SIMtrace v2.0 SIMtrace v2.0
The SIMtrace software together with the corresponding hardware provides a means to trace the communication between a SIM card and a mobile phone, and intercept it starting with SIMtrace software version 2.0 (together with SIMtrace board version 1.5). =============
Furthermore, it provides a SIM card emulation and CCID reader mode.
## How to compile This is the repository for the next-generation SIMtrace devices,
A Makefile is provided. It created an image under bin/project-flash.bin, which can directly be flashed on the board (see section "How to flash"). providing abilities to trace the communication between (U)SIM card and
phone, remote (U)SIM card forward, (U)SIM man-in-the-middle, and more.
The level of debug messages can be altered at compile time: This is under heavy development, and right now it is not surprising if
``` things still break on a daily basis.
$ make TRACE_LEVEL=4
```
Accepted values: 0 (NO_TRACE) to 5 (DEBUG)
## How to flash NOTE: Nothing in this repository applies to the SIMtrace v1.x hardware
For flashing the firmware, there are at least two options. or its associated firmware. SIMtrace v1.x is based on a different CPU /
The first one is using openocd and a JTAG key. microcontroller architecture and uses a completely different software
For this option, a JTAG connector has to be soldered onto the board, which is not attached per default. stack and host software.
The Makefile already provides an option for that: Supported Hardware
``` ------------------
$ make program
```
This command will call the following command:
```
$ openocd -f openocd/openocd.cfg -c "init" -c "halt" -c "flash write_bank 0 ./bin/project-flash.bin 0" -c "reset" -c "shutdown"
```
The second option is using rumba for flashing. No further hardware has to be provided for this option. At this point, the primary development target is still the OWHW + sysmoQMOD
The software can be obtained with the following shell command: device, but we expect to add support for a SAM3 based SIMtrace hardware
``` board soon.
$ git clone git://git.osmocom.org/osmo-sdr.git
```
Flashing the compiled firmware can be done with the following command: The goal is to support the following devices:
```
$ $OSMO_SDR_DIR/utils/rumba /dev/ttyACM0 flashmcu $FIRMWARE_DIR/bin/project-flash.bin
```
## How to set udev rules * Osmocom SIMtrace 1.x with SAM3 controller
The next step is defining the udev rules for simtrace. ** this is open hardware and schematics / PCB design is published
Open the file /etc/udev/rules.d/90-simtrace.rules and enter those four lines: * sysmocom sysmoQMOD (with 4 Modems, 4 SIM slots and 2 SAM3)
** this is a proprietary device, publicly available from sysmocom
* sysmocom OWHW (with 2 Modems and 1 SAM3 onboard)
** this is not publicly available hardware, but still supported
``` This Repository
# Temporary VID and PID ---------------
SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="6004", MODE="666"
# Future SIMtrace VID and PID
SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", ATTR{idProduct}=="0762)", MODE="666"
```
After reloading the udev rules, SIMtrace should be recognized by the operating system. This repository contains several directory
## How to use * firmware - the firmware to run on the actual devices
* hardware - some information related to the hardware
After flashing the firmware and defining the udev rules, the python program simtrace.py can be used in order to command the board. * host - Programs to use on the USB host to interface with the hardware
First, the configuration has to be set using the -C option, which has to be passed a number determining the mode:
1: Sniffer mode
2: CCID reader mode
3: Mobile phone emulation mode
4: MITM mode
For example, setting the device into MITM mode can be achieved with the following command:
```
$ simtrace.py -C4
```
After setting the configuration, one of the following functionalities can be started:
```
-s, --sniff Sniff communication!
-S, --select_file Transmit SELECT cmd!
-p, --phone Emulates simcard
-m, --mitm Intercept communication (MITM)
```
For example, in order to use simtrace in sniffer mode, the following command can be executed:
```
$ simtrace.py -C1 -s
```
For more information, execute the following command:
```
$ simtrace.py -h
```
## Logging
The Makefile furthermore provides an easy option for reading the log messages.
SIMtrace sends out log messages over the serial interface, using a connector with a 2.5mm jack.
Using a serial to USB converter, the log messages can be read using the following command:
```
$ make log SERIAL=/dev/ttyUSB*
```
If no SERIAL is defined, /dev/ttyUSB0 is taken by default.
## Known issues
* If there is an error, it might result from a missing instruction byte in the list of instructions that expect data from the simcard.
It can be updated in the file in apdu_split.py
Especially, if the sniffer mode works well, but the mitm mode fails, that's a good place to start looking.
The array is of the following form:
`INS_data_expected = [0xC0, 0xB0, 0x12]`
* For interacting with the SIM card (CCID reader and MITM mode), pcscd has to be
started on the computer.
* The maximum operating frequency of the device and hardware is not determined yet.
The function for changing the FIDI is not tested yet because no device could be obtained, which would change the FIDI in the middle of the communication.
Most devices stick with the default FIDI.
* The software assumes a master-slave-protocol: The master sends a command, the slave answers this.
If this premise is not met, the software will not operate properly.
This should be taken into account when programming the Mobile phone emulator or MITM mode.

79
contrib/jenkins.sh Executable file
View File

@@ -0,0 +1,79 @@
#!/bin/bash
TOPDIR=`pwd`
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
set -e
publish="$1"
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls'
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
BUILDS=""
BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play
BUILDS+="qmod/dfu qmod/cardem "
BUILDS+="owhw/dfu owhw/cardem "
cd $TOPDIR/firmware
for build in $BUILDS; do
board=`echo $build | cut -d "/" -f 1`
app=`echo $build | cut -d "/" -f 2`
echo
echo "=============== $board / $app START =============="
make BOARD="$board" APP="$app"
echo "=============== $board / $app RES:$? =============="
done
echo
echo "=============== FIRMWARE TESTS ==========="
cd $TOPDIR/firmware/test
make clean
make
./card_emu_test
make clean
echo
echo "=============== HOST START =============="
cd $TOPDIR/host
make clean
make
make clean
if [ "x$publish" = "x--publish" ]; then
echo
echo "=============== UPLOAD BUILD =============="
cat > "$WORKSPACE/known_hosts" <<EOF
[rita.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9
[rita.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54=
[rita.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX
EOF
SSH_COMMAND="ssh -o 'UserKnownHostsFile=$WORKSPACE/known_hosts' -p 48"
rsync -avz --delete -e "$SSH_COMMAND" $TOPDIR/firmware/bin/*.bin binaries@rita.osmocom.org:web-files/simtrace2/firmware/
fi
echo
echo "=============== FIRMWARE CLEAN =============="
cd $TOPDIR/firmware/
for build in $BUILDS; do
board=`echo $build | cut -d "/" -f 1`
app=`echo $build | cut -d "/" -f 2`
make BOARD="$board" APP="$app" clean
done
osmo-clean-workspace.sh

11
debian/changelog vendored Normal file
View File

@@ -0,0 +1,11 @@
simtrace2 (0.5.1) unstable; urgency=medium
* Backwards-compatibility with older (released, non-master) libosmocore
-- Harald Welte <lafore@gnumonks.org> Sun, 26 Aug 2018 11:50:36 +0200
simtrace2 (0.5) unstable; urgency=medium
* Initial debian package release.
-- Harald Welte <lafore@gnumonks.org> Sun, 26 Aug 2018 10:37:19 +0200

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

30
debian/control vendored Normal file
View File

@@ -0,0 +1,30 @@
Source: simtrace2
Maintainer: Harald Welte <laforge@gnumonks.org>
Section: devel
Priority: optional
Build-Depends: debhelper (>= 9),
libosmocore-dev,
libnewlib-arm-none-eabi,
libusb-1.0-0-dev,
gcc-arm-none-eabi
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/simtrace2.git
Vcs-Browser: http://git.osmocom.org/simtrace2/
Homepage: http://osmocom.org/projects/simtrace2/wiki
Package: simtrace2-firmware
Section: devel
Architecture: all
Recommends: dfu-util
Description: Firmware for SAM3 based SIMtrace2 USB Devices.
Open Source firmware for the Cortex-M3 microcontroller in the
"Osmocom SIMtrace2" USB-attached peripheral device. Will only work in
SAM3S-based SIMtrace2, not in its SAM7S-based predecessor SIMtrace!
Package: simtrace2-utils
Section: devel
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
Recommends: simtrace2-firmware
Description: Host utilities to communicate with SIMtrace2 USB Devices.

4
debian/rules vendored Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/make -f
%:
dh $@

1
debian/simtrace2-firmware.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/share/simtrace2/*.bin

1
debian/simtrace2-utils.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/bin/simtrace2-*

View File

@@ -95,9 +95,9 @@ C_OSMOCORE = $(notdir $(wildcard libosmocore/source/*.c))
C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard $(AT91LIB)/libchip_sam3s/cmsis/*.c)) C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard $(AT91LIB)/libchip_sam3s/cmsis/*.c))
C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c
C_LIBUSB_RT = dfu.c dfu_desc.c dfu_runtime.c C_LIBUSB_RT = dfu.c dfu_runtime.c
C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c
C_LIBCOMMON = string.c stdio.c fputs.c req_ctx.c ringbuffer.c C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c)) C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
@@ -139,17 +139,17 @@ INCLUDES += -Ilibboard/common/include -Ilibboard/$(BOARD)/include
INCLUDES += -Ilibcommon/include INCLUDES += -Ilibcommon/include
INCLUDES += -Ilibosmocore/include INCLUDES += -Ilibosmocore/include
INCLUDES += -Isrc_simtrace -Iinclude INCLUDES += -Isrc_simtrace -Iinclude
INCLUDES += -Iapps/$(APP)
CFLAGS += -Wall -Wchar-subscripts -Wcomment -Wimplicit-int #-Wformat=2 CFLAGS += -Wall -Wchar-subscripts -Wcomment -Wimplicit-int -Wformat=2
CFLAGS += -Werror-implicit-function-declaration -Wmain -Wparentheses CFLAGS += -Werror-implicit-function-declaration -Wmain -Wparentheses
CFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs #-Wunused CFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs #-Wunused
CFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef CFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal #-Wundef
CFLAGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings CFLAGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings
CFLAGS += -Wsign-compare -Waggregate-return CFLAGS += -Waggregate-return #-Wsign-compare
CFLAGS += -Wformat=0
CFLAGS += -Wmissing-format-attribute -Wno-deprecated-declarations CFLAGS += -Wmissing-format-attribute -Wno-deprecated-declarations
CFLAGS += #-Wpacked CFLAGS += #-Wpacked
CFLAGS += -Wredundant-decls -Wnested-externs -Winline #-Wlong-long CFLAGS += -Wredundant-decls -Wnested-externs #-Winline -Wlong-long
CFLAGS += -Wunreachable-code CFLAGS += -Wunreachable-code
#CFLAGS += -Wcast-align #CFLAGS += -Wcast-align
#CFLAGS += -std=c11 #CFLAGS += -std=c11
@@ -179,10 +179,25 @@ OUTPUT := $(BIN)/$(OUTPUT)
# Rules # Rules
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
all: $(BIN) $(OBJ) $(MEMORIES) all: apps/$(APP)/usb_strings_generated.h $(BIN) $(OBJ) $(MEMORIES)
combined: $(OUTPUT)-combined.bin
$(BIN)/$(BOARD)-dfu-flash-padded.bin: $(BIN)/$(BOARD)-dfu-flash.bin
dd if=/dev/zero bs=16384 count=1 of=$@
dd if=$< conv=notrunc of=$@
$(OUTPUT)-combined.bin: $(BIN)/$(BOARD)-dfu-flash-padded.bin $(OUTPUT)-dfu.bin
cat $^ > $@
$(BIN) $(OBJ): $(BIN) $(OBJ):
mkdir $@ mkdir -p $@
usbstring/usbstring: usbstring/usbstring.c
gcc $^ -o $@
apps/$(APP)/usb_strings_generated.h: apps/$(APP)/usb_strings.txt usbstring/usbstring
cat $< | usbstring/usbstring > $@
define RULES define RULES
C_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(C_OBJECTS)) C_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(C_OBJECTS))
@@ -217,4 +232,8 @@ log:
lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts ) lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts )
clean: clean:
-rm -fR $(OBJ)/*.o $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(BIN)/*.lst -rm -fR $(OBJ)/*.o $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(BIN)/*.lst `find . -name \*.p`
install:
mkdir -p $(DESTDIR)/usr/share/simtrace2
cp $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(DESTDIR)/usr/share/simtrace2

View File

@@ -1,33 +1,81 @@
This is the source code for SIMtrace 2 firmwares.
== BOARDS = Hardware
A board defines a given circuit board, i.e. SIMtrace, OWHW, QMOD == Micro-Controller
It defines the given hardware model for which the program is to be The firmware is for Microchip (formerly Atmel) ATSAM3S4B micro-controllers (MCU).
compiled. Product page: https://www.microchip.com/wwwproducts/en/ATSAM3S4B
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6500-32-bit-Cortex-M3-Microcontroller-SAM3S4-SAM3S2-SAM3S1_Datasheet.pdf
Note: The SAM3S is now not recommended for new designs.
It can be replaced by the pin-compatible SAM4S.
The MCU can be specified using the environment variable `CHIP` (set to `sam3s4` per default) for future MCU support.
== Boards
The SIMtrace 2 firmware supports multiple boards.
A board defines a given circuit board.
While compiling the firmware, set the target board using the `BOARD` environment variable (set to `qmod` per default).
The supported boards correspond to sub-folders under `libboard`.
Current boards supported are: Current boards supported are:
* simtrace: The good old Osmocom SIMtrace PCB with SAM3 instead of
SAM7, open hardware.
* qmod: A sysmocom-proprietary quad mPCIe carrier board, publicly available
* owhw: An undisclosed sysmocom-internal board, not publicly available
== APPLICATIONS * `simtrace`: The good old Osmocom SIMtrace PCB with SAM3 instead of SAM7, open hardware.
* `qmod`: A sysmocom-proprietary quad mPCIe carrier board, publicly available
* `owhw`: An undisclosed sysmocom-internal board, not publicly available
An application is a specific piece of software with given = Firmware
functionality.
== ENVIRONMENTS == Library
The firmware uses the manufacturer provided Software Package (SoftPack) micro-controller library.
The original library is available at https://www.microchip.com/design-centers/32-bit/softpacks/legacy-softpacks .
Version 2.1 from 2001 is used: http://ww1.microchip.com/downloads/en/DeviceDoc/SAM3S_softpack_2.1_for_CodeSourcery_2010q1.zip
The SIMtrace 2 project uses the `libboard_sam3s-ek`, `libchip_sam3s`, and `usb` sub-libraries, saved in `atmel_softpack_libraries` (with local modifications).
Note: SoftPack is the legacy micro-controller library.
This library is now replaced by the Advanced Software Framework (ASF): https://www.microchip.com/avr-support/advanced-software-framework-(asf) .
The SAM3S ASF documentation is available at http://asf.atmel.com/docs/latest/sam3s/html/index.html .
== Applications
An application is a specific piece of software with given functionality.
While compiling the firmware, set the target application using the `APP` environment variable (set to `dfu` per default).
The supported applications correspond to sub-folder under `apps`.
Current applications supported are:
* `dfu`: The USB DFU bootloader to flash further main appliction firmwares.
* `ccid`: To use SIMtrace 2 as USB CCID smartcard reader.
* `cardem`: To provide remote SIM operation capabilities.
* `trace`: To monitor the communication between a SIM card and a phone (corresponds to the functionality provide by the first SIMtrace)
* `triple_play`: To support the three previous functionalities, using USB configurations.
== Memories
Firmwares can be run from several memory locations:
An environment is a runtime environment, typically defined by a linker
script. The current runtime environments include
* flash: Run natively from start of flash memory * flash: Run natively from start of flash memory
* dfu: Run after a DFU bootloader from an offset after the first 16k * dfu: Run after a DFU bootloader from an offset after the first 16k of flash (the first 16k are reserved for the bootloader)
of flash (the first 16k are reserved for the bootloader)
* ram: Run from within the RAM of the chip, downloaded via JTAG/SWD * ram: Run from within the RAM of the chip, downloaded via JTAG/SWD
== Building == Building
A given software build is made for a specific combination of an APP A given firmware build is made for a specific combination of an application `APP` running in a certain memory `MEM` on a given board `BOARD`.
running in a certain ENVIRONMENT on a given BOARD. When building using `make`, set the target application using the `APP` environment variable and target board using the `BOARD` environment variable, e.g.:
* make APP=cardem BOARD=qmod
* make APP=dfu BOARD=qmod
The Makefile will create output files in the format: `bin/$(BOARD)-$(APP)-$(MEM).{elf,bin}`
The level of debug messages can be altered at compile time:
```
$ make TRACE_LEVEL=4
```
Accepted values: 0 (NO_TRACE) to 5 (DEBUG)
= Flashing
To flash a firmware image follow the instructions provided in the [wiki](https://projects.osmocom.org/projects/simtrace2/wiki/).

22
firmware/TODO.txt Normal file
View File

@@ -0,0 +1,22 @@
== Important DFU topics / reliability ==
x some kind of DFU fallback / boot cycle counter ?
* CRC check of image before attempting to execute it ?
x Keep WDT running while in DFU or app
? USB control request for flash erase
== QModem related ==
x new vendor/product ID for hub and SAM3s
* board-specfic string descriptors
* re-mapping of USB ports in EEPROM
== Lower Priority ==
* unique serial number in iSerial?
* printing of banner from generic function
* board_main_top() automatically before calling main()
x compile-time USB string generation
* shared USB strings for DFU and runtime
* version detection voltage ranges
* locking of bootloader pages?
* debug console command for switch-to-dfu
* read CPU reset cause (and time?) via USB

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT) C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c ccid.c host_communication.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c

View File

@@ -1,4 +1,21 @@
// FIXME: Copyright license here /* SIMtrace 2 firmware card emulation application
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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
*/
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
@@ -6,8 +23,7 @@
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "req_ctx.h" #include <osmocom/core/timer.h>
#include "osmocom/core/timer.h"
unsigned int g_unique_id[4]; unsigned int g_unique_id[4];
@@ -90,11 +106,13 @@ void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum)
void USART1_IrqHandler(void) void USART1_IrqHandler(void)
{ {
if (config_func_ptrs[simtrace_config].usart1_irq)
config_func_ptrs[simtrace_config].usart1_irq(); config_func_ptrs[simtrace_config].usart1_irq();
} }
void USART0_IrqHandler(void) void USART0_IrqHandler(void)
{ {
if (config_func_ptrs[simtrace_config].usart0_irq)
config_func_ptrs[simtrace_config].usart0_irq(); config_func_ptrs[simtrace_config].usart0_irq();
} }
@@ -107,6 +125,8 @@ static void check_exec_dbg_cmd(void)
return; return;
ch = UART_GetChar(); ch = UART_GetChar();
/* We must echo the character to make python fdexpect happy, whcih we use in factory testing */
fputc(ch, stdout);
board_exec_dbg_cmd(ch); board_exec_dbg_cmd(ch);
} }
@@ -121,58 +141,75 @@ extern int main(void)
enum confNum last_simtrace_config = simtrace_config; enum confNum last_simtrace_config = simtrace_config;
unsigned int i = 0; unsigned int i = 0;
LED_Configure(LED_NUM_RED); led_init();
LED_Configure(LED_NUM_GREEN); led_blink(LED_RED, BLINK_3O_5F);
LED_Set(LED_NUM_RED);
/* Disable watchdog */ /* Enable watchdog for 2000ms, with no window */
WDT_Disable(WDT); WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
(WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
req_ctx_init();
PIO_InitializeInterrupts(0); PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id); EEFC_ReadUniqueID(g_unique_id);
printf("\r\n\r\n" printf("\n\r\n\r"
"=============================================================================\r\n" "=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\r\n" "SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r"
"=============================================================================\r\n"); "=============================================================================\n\r");
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\r\n", #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1], g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]); g_unique_id[2], g_unique_id[3]);
uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
static const char* reset_causes[] = {
"general reset (first power-up reset)",
"backup reset (return from backup mode)",
"watchdog reset (watchdog fault occurred)",
"software reset (processor reset required by the software)",
"user reset (NRST pin detected low)",
};
if (reset_cause < ARRAY_SIZE(reset_causes)) {
TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]);
} else {
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
}
#endif
board_main_top(); board_main_top();
TRACE_INFO("USB init...\r\n"); TRACE_INFO("USB init...\n\r");
SIMtrace_USB_Initialize(); SIMtrace_USB_Initialize();
while (USBD_GetState() < USBD_STATE_CONFIGURED) { while (USBD_GetState() < USBD_STATE_CONFIGURED) {
WDT_Restart(WDT);
check_exec_dbg_cmd(); check_exec_dbg_cmd();
#if 0 #if 0
if (i >= MAX_USB_ITER * 3) { if (i >= MAX_USB_ITER * 3) {
TRACE_ERROR("Resetting board (USB could " TRACE_ERROR("Resetting board (USB could "
"not be configured)\r\n"); "not be configured)\n\r");
USBD_Disconnect();
NVIC_SystemReset(); NVIC_SystemReset();
} }
#endif #endif
i++; i++;
} }
TRACE_INFO("calling configure of all configurations...\r\n"); TRACE_INFO("calling configure of all configurations...\n\r");
for (i = 1; i < sizeof(config_func_ptrs) / sizeof(config_func_ptrs[0]); for (i = 1; i < sizeof(config_func_ptrs) / sizeof(config_func_ptrs[0]);
++i) { ++i) {
if (config_func_ptrs[i].configure) if (config_func_ptrs[i].configure)
config_func_ptrs[i].configure(); config_func_ptrs[i].configure();
} }
TRACE_INFO("calling init of config %u...\r\n", simtrace_config); TRACE_INFO("calling init of config %u...\n\r", simtrace_config);
config_func_ptrs[simtrace_config].init(); config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config; last_simtrace_config = simtrace_config;
TRACE_INFO("entering main loop...\r\n"); TRACE_INFO("entering main loop...\n\r");
while (1) { while (1) {
WDT_Restart(WDT);
#if TRACE_LEVEL >= TRACE_LEVEL_DEBUG #if TRACE_LEVEL >= TRACE_LEVEL_DEBUG
const char rotor[] = { '-', '\\', '|', '/' }; const char rotor[] = { '-', '\\', '|', '/' };
putchar('\b'); putchar('\b');
@@ -188,14 +225,12 @@ extern int main(void)
isUsbConnected = 0; isUsbConnected = 0;
} }
} else if (isUsbConnected == 0) { } else if (isUsbConnected == 0) {
TRACE_INFO("USB is now configured\r\n"); TRACE_INFO("USB is now configured\n\r");
LED_Set(LED_NUM_GREEN);
LED_Clear(LED_NUM_RED);
isUsbConnected = 1; isUsbConnected = 1;
} }
if (last_simtrace_config != simtrace_config) { if (last_simtrace_config != simtrace_config) {
TRACE_INFO("USB config chg %u -> %u\r\n", TRACE_INFO("USB config chg %u -> %u\n\r",
last_simtrace_config, simtrace_config); last_simtrace_config, simtrace_config);
config_func_ptrs[last_simtrace_config].exit(); config_func_ptrs[last_simtrace_config].exit();
config_func_ptrs[simtrace_config].init(); config_func_ptrs[simtrace_config].init();

View File

@@ -0,0 +1,10 @@
sysmocom - s.f.m.c. GmbH
SIMtrace 2 compatible device
SIMtrace Sniffer
SIMtrace CCID
SIMtrace Phone
SIMtrace MITM
CardEmulator Modem 1
CardEmulator Modem 2
CardEmulator Modem 3
CardEmulator Modem 4

View File

@@ -1,13 +1,43 @@
/* SIMtrace 2 firmware USB DFU bootloader
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "board.h" #include "board.h"
#include "utils.h" #include "utils.h"
#include "usb/device/dfu/dfu.h" #include "usb/device/dfu/dfu.h"
#include "usb/common/dfu/usb_dfu.h" #include "usb/common/dfu/usb_dfu.h"
#include "manifest.h" #include "manifest.h"
#include "USBD_HAL.h"
#include <osmocom/core/timer.h>
#define ALTIF_RAM 0 #define ALTIF_RAM 0
#define ALTIF_FLASH 1 #define ALTIF_FLASH 1
unsigned int g_unique_id[4]; unsigned int g_unique_id[4];
/* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */
static bool watchdog_configured = false;
/* There is not enough space in the 16 KiB DFU bootloader to include led.h functions */
#ifdef PINS_LEDS
/** LED pin configurations */
static const Pin pinsLeds[] = { PINS_LEDS } ;
#endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Callbacks * Callbacks
@@ -19,46 +49,81 @@ unsigned int g_unique_id[4];
#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE) #define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)
#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE) #define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)
/* incoming call-back: Host has transfered 'len' bytes (stored at /* incoming call-back: Host has transferred 'len' bytes (stored at
* 'data'), which we shall write to 'offset' into the partition * 'data'), which we shall write to 'offset' into the partition
* associated with 'altif'. Guaranted to be les than * associated with 'altif'. Guaranted to be less than
* BOARD_DFU_PAGE_SIZE */ * BOARD_DFU_PAGE_SIZE */
int USBDFU_handle_dnload(uint8_t altif, unsigned int offset, int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
uint8_t *data, unsigned int len) uint8_t *data, unsigned int len)
{ {
uint32_t addr; uint32_t addr;
unsigned int i;
int rc; int rc;
/* address of the last allocated variable on the stack */
uint32_t stack_addr = (uint32_t)&rc;
/* kick the dog to have enough time to flash */
if (watchdog_configured) {
WDT_Restart(WDT);
}
printf("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len); printf("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len);
#ifdef PINS_LEDS
PIO_Clear(&pinsLeds[LED_NUM_RED]);
#endif
switch (altif) { switch (altif) {
case ALTIF_RAM: case ALTIF_RAM:
addr = RAM_ADDR(offset); addr = RAM_ADDR(offset);
if (addr > IRAM_ADDR + IRAM_SIZE) { if (addr < IRAM_ADDR || addr + len >= IRAM_ADDR + IRAM_SIZE || addr + len >= stack_addr) {
g_dfu->state = DFU_STATE_dfuERROR; g_dfu->state = DFU_STATE_dfuERROR;
g_dfu->status = DFU_STATUS_errADDRESS; g_dfu->status = DFU_STATUS_errADDRESS;
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
} }
memcpy((void *)addr, data, len); memcpy((void *)addr, data, len);
return DFU_RET_ZLP; rc = DFU_RET_ZLP;
break;
case ALTIF_FLASH: case ALTIF_FLASH:
addr = FLASH_ADDR(offset); addr = FLASH_ADDR(offset);
if (addr > IFLASH_ADDR + IFLASH_SIZE) { if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + IFLASH_SIZE) {
g_dfu->state = DFU_STATE_dfuERROR; g_dfu->state = DFU_STATE_dfuERROR;
g_dfu->status = DFU_STATUS_errADDRESS; g_dfu->status = DFU_STATUS_errADDRESS;
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
}
rc = FLASHD_Unlock(addr, addr + len, 0, 0);
if (rc != 0) {
TRACE_ERROR("DFU download flash unlock failed\n\r");
rc = DFU_RET_STALL;
break;
} }
rc = FLASHD_Write(addr, data, len); rc = FLASHD_Write(addr, data, len);
if (rc != 0) { if (rc != 0) {
/* FIXME: set error codes */ TRACE_ERROR("DFU download flash erase failed\n\r");
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
} }
return DFU_RET_ZLP; for (i = 0; i < len; i++) {
if (((uint8_t*)addr)[i]!=data[i]) {
TRACE_ERROR("DFU download flash data written not correct\n\r");
rc = DFU_RET_STALL;
break;
}
}
rc = DFU_RET_ZLP;
break;
default: default:
/* FIXME: set error codes */
TRACE_ERROR("DFU download for unknown AltIf %d\n\r", altif); TRACE_ERROR("DFU download for unknown AltIf %d\n\r", altif);
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
} }
#ifdef PINS_LEDS
PIO_Set(&pinsLeds[LED_NUM_RED]);
#endif
return rc;
} }
/* incoming call-back: Host has requested to read back 'req_len' bytes /* incoming call-back: Host has requested to read back 'req_len' bytes
@@ -99,10 +164,48 @@ int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
/* FIXME: set error codes */ /* FIXME: set error codes */
return -1; return -1;
} }
printf("=%u\r\n", req_len); printf("=%u\n\r", req_len);
return req_len; return req_len;
} }
/* can be overridden by board specific code, e.g. by pushbutton */
WEAK int board_override_enter_dfu(void)
{
return 0;
}
/* using this function we can determine if we should enter DFU mode
* during boot, or if we should proceed towards the application/runtime */
int USBDFU_OverrideEnterDFU(void)
{
uint32_t *app_part = (uint32_t *)FLASH_ADDR(0);
/* at the first call we are before the text segment has been relocated,
* so g_dfu is not initialized yet */
g_dfu = &_g_dfu;
if (USB_DFU_MAGIC == g_dfu->magic) {
return 1;
}
/* If the loopback jumper is set, we enter DFU mode */
if (board_override_enter_dfu()) {
return 2;
}
/* if the first word of the application partition doesn't look
* like a stack pointer (i.e. point to RAM), enter DFU mode */
if ((app_part[0] < IRAM_ADDR) || ((uint8_t *)app_part[0] > IRAM_END)) {
return 3;
}
/* if the second word of the application partition doesn't look
* like a function from flash (reset vector), enter DFU mode */
if (((uint32_t *)app_part[1] < app_part) ||
((uint8_t *)app_part[1] > IFLASH_END)) {
return 4;
}
return 0;
}
/* returns '1' in case we should break any endless loop */ /* returns '1' in case we should break any endless loop */
static void check_exec_dbg_cmd(void) static void check_exec_dbg_cmd(void)
@@ -125,59 +228,117 @@ extern int main(void)
{ {
uint8_t isUsbConnected = 0; uint8_t isUsbConnected = 0;
unsigned int i = 0; unsigned int i = 0;
uint32_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
LED_Configure(LED_NUM_RED); /* Enable watchdog for 2000ms, with no window */
LED_Configure(LED_NUM_GREEN); WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
LED_Set(LED_NUM_RED); (WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
watchdog_configured = true;
/* Disable watchdog */ #ifdef PINS_LEDS
WDT_Disable(WDT); /* Configure LED */
PIO_Configure(pinsLeds, sizeof(pinsLeds));
//req_ctx_init(); PIO_Set(&pinsLeds[LED_NUM_RED]);
PIO_Clear(&pinsLeds[LED_NUM_GREEN]);
#endif
PIO_InitializeInterrupts(0); PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id); EEFC_ReadUniqueID(g_unique_id);
printf("\r\n\r\n" printf("\n\r\n\r"
"=============================================================================\r\n" "=============================================================================\n\r"
"DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\r\n" "DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\n\r"
"=============================================================================\r\n", "=============================================================================\n\r",
manifest_revision, manifest_board); manifest_revision, manifest_board);
TRACE_INFO("Chip ID: 0x%08x (Ext 0x%08x)\r\n", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); TRACE_INFO("Chip ID: 0x%08x (Ext 0x%08x)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\r\n", TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1], g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]); g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%x\n\r", reset_cause);
//board_main_top(); #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
/* Find out why we are in the DFU bootloader, and not the main application */
TRACE_INFO("DFU bootloader start reason: ");
switch (USBDFU_OverrideEnterDFU()) {
case 0:
/* 0 normally means that there is no override, but we are in the bootloader,
* thus the first check in board_cstartup_gnu did return something else than 0.
* this can only be g_dfu->magic which is erased when the segment are
* relocated, which happens in board_cstartup_gnu just after USBDFU_OverrideEnterDFU.
* no static variable can be used to store this case since this will also be overwritten
*/
case 1:
TRACE_INFO_WP("DFU switch requested by main application\n\r");
break;
case 2:
TRACE_INFO_WP("bootloader forced (button pressed or jumper set)\n\r");
break;
case 3:
TRACE_INFO_WP("stack pointer (first application word) does no point in RAM\n\r");
break;
case 4: // the is no reason
TRACE_INFO_WP("reset vector (second application word) does no point in flash\n\r");
break;
default:
TRACE_INFO_WP("unknown\n\r");
break;
}
#endif
/* clear g_dfu on power-up reset */
if (reset_cause == 0)
memset(g_dfu, 0, sizeof(*g_dfu));
board_main_top();
TRACE_INFO("USB init...\n\r");
/* Signal USB reset by disabling the pull-up on USB D+ for at least 10 ms */
#ifdef PIN_USB_PULLUP
const Pin usb_dp_pullup = PIN_USB_PULLUP;
PIO_Configure(&usb_dp_pullup, 1);
PIO_Set(&usb_dp_pullup);
#endif
USBD_HAL_Suspend();
mdelay(20);
#ifdef PIN_USB_PULLUP
PIO_Clear(&usb_dp_pullup);
#endif
USBD_HAL_Activate();
TRACE_INFO("USB init...\r\n");
USBDFU_Initialize(&dfu_descriptors); USBDFU_Initialize(&dfu_descriptors);
while (USBD_GetState() < USBD_STATE_CONFIGURED) { while (USBD_GetState() < USBD_STATE_CONFIGURED) {
WDT_Restart(WDT);
check_exec_dbg_cmd(); check_exec_dbg_cmd();
#if 1 #if 1
if (i >= MAX_USB_ITER * 3) { if (i >= MAX_USB_ITER * 3) {
TRACE_ERROR("Resetting board (USB could " TRACE_ERROR("Resetting board (USB could "
"not be configured)\r\n"); "not be configured)\n\r");
USBD_Disconnect();
NVIC_SystemReset(); NVIC_SystemReset();
} }
#endif #endif
i++; i++;
} }
/* Initialize the flash to be able to write it, using the IAP ROM code */
FLASHD_Initialize(BOARD_MCK, 1); FLASHD_Initialize(BOARD_MCK, 1);
TRACE_INFO("entering main loop...\r\n");
TRACE_INFO("entering main loop...\n\r");
while (1) { while (1) {
WDT_Restart(WDT);
#if TRACE_LEVEL >= TRACE_LEVEL_DEBUG #if TRACE_LEVEL >= TRACE_LEVEL_DEBUG
const char rotor[] = { '-', '\\', '|', '/' }; const char rotor[] = { '-', '\\', '|', '/' };
putchar('\b'); putchar('\b');
putchar(rotor[i++ % ARRAY_SIZE(rotor)]); putchar(rotor[i++ % ARRAY_SIZE(rotor)]);
#endif #endif
check_exec_dbg_cmd(); check_exec_dbg_cmd();
//osmo_timers_prepare(); #if 0
//osmo_timers_update(); osmo_timers_prepare();
osmo_timers_update();
#endif
if (USBD_GetState() < USBD_STATE_CONFIGURED) { if (USBD_GetState() < USBD_STATE_CONFIGURED) {
@@ -185,9 +346,7 @@ extern int main(void)
isUsbConnected = 0; isUsbConnected = 0;
} }
} else if (isUsbConnected == 0) { } else if (isUsbConnected == 0) {
TRACE_INFO("USB is now configured\r\n"); TRACE_INFO("USB is now configured\n\r");
LED_Set(LED_NUM_GREEN);
LED_Clear(LED_NUM_RED);
isUsbConnected = 1; isUsbConnected = 1;
} }

View File

@@ -0,0 +1,5 @@
sysmocom - s.f.m.c. GmbH
SIMtrace 2 compatible device
DFU (Device Firmware Upgrade)
RAM
Flash (Application Partition)

View File

@@ -0,0 +1,3 @@
C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c

View File

@@ -0,0 +1,236 @@
/* SIMtrace 2 firmware sniffer application
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "board.h"
#include "simtrace.h"
#include "utils.h"
#include "osmocom/core/timer.h"
unsigned int g_unique_id[4];
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
typedef struct {
/* static initialization, called whether or not the usb config is active */
void (*configure) (void);
/* initialization function after the config was selected */
void (*init) (void);
/* de-initialization before selecting new config */
void (*exit) (void);
/* main loop content for given configuration */
void (*run) (void);
/* Interrupt handler for USART0 */
void (*usart0_irq) (void);
/* Interrupt handler for USART1 */
void (*usart1_irq) (void);
} conf_func;
static const conf_func config_func_ptrs[] = {
/* array slot 0 is empty, usb configs start at 1 */
#ifdef HAVE_SNIFFER
[CFG_NUM_SNIFF] = {
.configure = Sniffer_configure,
.init = Sniffer_init,
.exit = Sniffer_exit,
.run = Sniffer_run,
.usart0_irq = Sniffer_usart0_irq,
.usart1_irq = Sniffer_usart1_irq,
},
#endif
#ifdef HAVE_CCID
[CFG_NUM_CCID] = {
.configure = CCID_configure,
.init = CCID_init,
.exit = CCID_exit,
.run = CCID_run,
},
#endif
#ifdef HAVE_CARDEM
[CFG_NUM_PHONE] = {
.configure = mode_cardemu_configure,
.init = mode_cardemu_init,
.exit = mode_cardemu_exit,
.run = mode_cardemu_run,
.usart0_irq = mode_cardemu_usart0_irq,
.usart1_irq = mode_cardemu_usart1_irq,
},
#endif
#ifdef HAVE_MITM
[CFG_NUM_MITM] = {
.configure = MITM_configure,
.init = MITM_init,
.exit = MITM_exit,
.run = MITM_run,
},
#endif
};
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
#if defined(HAVE_SNIFFER)
static volatile enum confNum simtrace_config = CFG_NUM_SNIFF;
#elif defined(HAVE_CARDEM)
static volatile enum confNum simtrace_config = CFG_NUM_PHONE;
#elif defined(HAVE_CCID)
static volatile enum confNum simtrace_config = CFG_NUM_CCID;
#endif
/*----------------------------------------------------------------------------
* Callbacks
*----------------------------------------------------------------------------*/
void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum)
{
TRACE_INFO_WP("cfgChanged%d ", cfgnum);
simtrace_config = cfgnum;
}
void USART1_IrqHandler(void)
{
if (config_func_ptrs[simtrace_config].usart1_irq)
config_func_ptrs[simtrace_config].usart1_irq();
}
void USART0_IrqHandler(void)
{
if (config_func_ptrs[simtrace_config].usart0_irq)
config_func_ptrs[simtrace_config].usart0_irq();
}
/* returns '1' in case we should break any endless loop */
static void check_exec_dbg_cmd(void)
{
int ch;
if (!UART_IsRxReady())
return;
ch = UART_GetChar();
board_exec_dbg_cmd(ch);
}
/*------------------------------------------------------------------------------
* Main
*------------------------------------------------------------------------------*/
#define MAX_USB_ITER BOARD_MCK/72 // This should be around a second
extern int main(void)
{
uint8_t isUsbConnected = 0;
enum confNum last_simtrace_config = simtrace_config;
unsigned int i = 0;
/* Configure LED output
* red on = power
* red blink = error
* green on = running
* green blink = activity
*/
led_init();
led_blink(LED_RED, BLINK_ALWAYS_ON);
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
/* Enable watchdog for 2000 ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
(WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
"=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r"
"=============================================================================\n\r");
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
TRACE_INFO("USB configuration used: %d\n\r", simtrace_config);
board_main_top();
TRACE_INFO("USB init...\n\r");
SIMtrace_USB_Initialize();
while (USBD_GetState() < USBD_STATE_CONFIGURED) {
WDT_Restart(WDT);
check_exec_dbg_cmd();
#if 0
if (i >= MAX_USB_ITER * 3) {
TRACE_ERROR("Resetting board (USB could "
"not be configured)\n\r");
USBD_Disconnect();
NVIC_SystemReset();
}
#endif
i++;
}
TRACE_INFO("calling configure of all configurations...\n\r");
for (i = 1; i < ARRAY_SIZE(config_func_ptrs); i++) {
if (config_func_ptrs[i].configure)
config_func_ptrs[i].configure();
}
TRACE_INFO("calling init of config %u...\n\r", simtrace_config);
config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config;
TRACE_INFO("entering main loop...\n\r");
while (1) {
WDT_Restart(WDT);
#if TRACE_LEVEL >= TRACE_LEVEL_DEBUG
const char rotor[] = { '-', '\\', '|', '/' };
putchar('\b');
putchar(rotor[i++ % ARRAY_SIZE(rotor)]);
#endif
check_exec_dbg_cmd();
osmo_timers_prepare();
osmo_timers_update();
if (USBD_GetState() < USBD_STATE_CONFIGURED) {
if (isUsbConnected) {
isUsbConnected = 0;
}
} else if (isUsbConnected == 0) {
TRACE_INFO("USB is now configured\n\r");
isUsbConnected = 1;
}
if (last_simtrace_config != simtrace_config) {
TRACE_INFO("USB config chg %u -> %u\n\r",
last_simtrace_config, simtrace_config);
config_func_ptrs[last_simtrace_config].exit();
config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config;
} else {
config_func_ptrs[simtrace_config].run();
}
}
}

View File

@@ -0,0 +1,10 @@
sysmocom - s.f.m.c. GmbH
SIMtrace 2 compatible device
SIMtrace Sniffer
SIMtrace CCID
SIMtrace Phone
SIMtrace MITM
CardEmulator Modem 1
CardEmulator Modem 2
CardEmulator Modem 3
CardEmulator Modem 4

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT) C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c ccid.c host_communication.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c C_FILES += card_emu.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c

View File

@@ -1,4 +1,21 @@
// FIXME: Copyright license here /* SIMtrace 2 firmware card emulation, CCID, and sniffer application
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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
*/
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
@@ -7,7 +24,7 @@
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "req_ctx.h" #include "req_ctx.h"
#include "osmocom/core/timer.h" #include <osmocom/core/timer.h>
unsigned int g_unique_id[4]; unsigned int g_unique_id[4];
@@ -154,6 +171,7 @@ extern int main(void)
if (i >= MAX_USB_ITER * 3) { if (i >= MAX_USB_ITER * 3) {
TRACE_ERROR("Resetting board (USB could " TRACE_ERROR("Resetting board (USB could "
"not be configured)\r\n"); "not be configured)\r\n");
USBD_Disconnect();
NVIC_SystemReset(); NVIC_SystemReset();
} }
#endif #endif

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -42,6 +43,7 @@
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#define printf printf_sync
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
@@ -81,7 +83,7 @@ struct hardfault_args {
void hard_fault_handler_c(struct hardfault_args *args) void hard_fault_handler_c(struct hardfault_args *args)
{ {
printf("HardFault\r\n"); printf("\r\nHardFault\r\n");
printf("R0=%08x, R1=%08x, R2=%08x, R3=%08x, R12=%08x\r\n", printf("R0=%08x, R1=%08x, R2=%08x, R3=%08x, R12=%08x\r\n",
args->r0, args->r1, args->r2, args->r3, args->r12); args->r0, args->r1, args->r2, args->r3, args->r12);
printf("LR[R14]=%08x, PC[R15]=%08x, PSR=%08x\r\n", printf("LR[R14]=%08x, PC[R15]=%08x, PSR=%08x\r\n",
@@ -90,6 +92,52 @@ void hard_fault_handler_c(struct hardfault_args *args)
SCB->BFAR, SCB->CFSR, SCB->HFSR); SCB->BFAR, SCB->CFSR, SCB->HFSR);
printf("DFSR=%08x, AFSR=%08x, SHCSR=%08x\r\n", printf("DFSR=%08x, AFSR=%08x, SHCSR=%08x\r\n",
SCB->DFSR, SCB->CFSR, SCB->SHCSR); SCB->DFSR, SCB->CFSR, SCB->SHCSR);
if (SCB->HFSR & 0x40000000)
printf("FORCED ");
if (SCB->HFSR & 0x00000002)
printf("VECTTBL ");
uint32_t ufsr = SCB->CFSR >> 16;
if (ufsr & 0x0200)
printf("DIVBYZERO ");
if (ufsr & 0x0100)
printf("UNALIGNED ");
if (ufsr & 0x0008)
printf("NOCP ");
if (ufsr & 0x0004)
printf("INVPC ");
if (ufsr & 0x0002)
printf("INVSTATE ");
if (ufsr & 0x0001)
printf("UNDEFINSTR ");
uint32_t bfsr = (SCB->CFSR >> 8) & 0xff;
if (bfsr & 0x80)
printf("BFARVALID ");
if (bfsr & 0x10)
printf("STKERR ");
if (bfsr & 0x08)
printf("UNSTKERR ");
if (bfsr & 0x04)
printf("IMPRECISERR ");
if (bfsr & 0x02)
printf("PRECISERR ");
if (bfsr & 0x01)
printf("IBUSERR ");
uint32_t mmfsr = (SCB->CFSR & 0xff);
if (mmfsr & 0x80)
printf("MMARVALID ");
if (mmfsr & 0x10)
printf("MSTKERR ");
if (mmfsr & 0x08)
printf("MUNSTKERR ");
if (mmfsr & 0x02)
printf("DACCVIOL ");
if (mmfsr & 0x01)
printf("IACCVIOL ");
while ( 1 ) ; while ( 1 ) ;
} }

View File

@@ -47,6 +47,8 @@
#include "USBD.h" #include "USBD.h"
#include "USBD_HAL.h" #include "USBD_HAL.h"
extern void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Definitions * Definitions
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
@@ -144,7 +146,11 @@ void USBD_RequestHandler(uint8_t bEndpoint,
bEndpoint); bEndpoint);
} }
else { else {
#if defined(BOARD_USB_DFU) && !defined(APPLICATION_dfu)
USBDFU_Runtime_RequestHandler(pRequest);
#else
USBDCallbacks_RequestReceived(pRequest); USBDCallbacks_RequestReceived(pRequest);
#endif
} }
} }

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation * Copyright (c) 2008, Atmel Corporation
* Copyright (c) 2018, Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -331,8 +332,13 @@ static void GetDescriptor(
/* Check if descriptor exists */ /* Check if descriptor exists */
if (indexRDesc >= numStrings) { if (indexRDesc >= numStrings) {
/* Sometimes descriptor string 0xee is requested.
USBD_Stall(0); * This is a mechanism used by Microsoft Windows to further identify the USB device.
* Instead of stalling, as is the original code, leading to an USB reset, we send an empty packet.
* I am not sure if sending an empty string would be better, but an empty packet seems sufficient.
*/
//USBD_Stall(0);
USBD_Write(0, NULL, 0, 0, 0);
} }
else { else {

View File

@@ -78,8 +78,8 @@ extern const USBDDriverDescriptors dfu_descriptors;
/* no DFU bootloader is being used */ /* no DFU bootloader is being used */
#define DFURT_NUM_IF 0 #define DFURT_NUM_IF 0
#define DFURT_IF_DESCRIPTOR_STRUCT(a, b) #define DFURT_IF_DESCRIPTOR_STRUCT
#define DFURT_IF_DESCRIPTOR #define DFURT_IF_DESCRIPTOR(a, b)
#endif /* BOARD_USB_DFU */ #endif /* BOARD_USB_DFU */
@@ -110,6 +110,7 @@ extern int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
uint8_t *data, unsigned int len); uint8_t *data, unsigned int len);
extern int USBDFU_handle_upload(uint8_t altif, unsigned int offset, extern int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
uint8_t *data, unsigned int req_len); uint8_t *data, unsigned int req_len);
extern int USBDFU_OverrideEnterDFU(void);
/* function to be called at end of EP0 handler during runtime */ /* function to be called at end of EP0 handler during runtime */
void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request); void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);

View File

@@ -28,9 +28,9 @@ static const USBDeviceDescriptor fsDevice = {
.bDeviceClass = 0, .bDeviceClass = 0,
.bDeviceSubClass = 0, .bDeviceSubClass = 0,
.bDeviceProtocol = 0, .bDeviceProtocol = 0,
.bMaxPacketSize0 = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), .bMaxPacketSize0 = USBEndpointDescriptor_MAXCTRLSIZE_FS,
.idVendor = BOARD_USB_VENDOR, .idVendor = BOARD_USB_VENDOR_ID,
.idProduct = BOARD_USB_PRODUCT, .idProduct = BOARD_DFU_USB_PRODUCT_ID,
.bcdDevice = BOARD_USB_RELEASE, .bcdDevice = BOARD_USB_RELEASE,
.iManufacturer = STR_MANUF, .iManufacturer = STR_MANUF,
.iProduct = STR_PROD, .iProduct = STR_PROD,
@@ -85,114 +85,13 @@ const struct dfu_desc dfu_cfg_descriptor = {
.func_dfu = DFU_FUNC_DESC .func_dfu = DFU_FUNC_DESC
}; };
#include "usb_strings_generated.h"
#if 0 #if 0
#include "usb_strings.h"
static const unsigned char *usb_strings[] = {
USB_STRINGS_GENERATED
#ifdef BOARD_USB_SERIAL
NULL
#endif
};
void set_usb_serial_str(const uint8_t *serial_usbstr) void set_usb_serial_str(const uint8_t *serial_usbstr)
{ {
usb_strings[STR_SERIAL] = serial_usbstr; usb_strings[STR_SERIAL] = serial_usbstr;
} }
#else
static const unsigned char langDesc[] = {
USBStringDescriptor_LENGTH(1),
USBGenericDescriptor_STRING,
USBStringDescriptor_ENGLISH_US
};
static const unsigned char manufStringDescriptor[] = {
USBStringDescriptor_LENGTH(24),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('y'),
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('-'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE('f'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('G'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('b'),
USBStringDescriptor_UNICODE('H'),
};
static const unsigned char productStringDescriptor[] = {
USBStringDescriptor_LENGTH(10),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('2'),
};
static const unsigned char configStringDescriptor[] = {
USBStringDescriptor_LENGTH(3),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('D'),
USBStringDescriptor_UNICODE('F'),
USBStringDescriptor_UNICODE('U'),
};
static const unsigned char altRamStringDescriptor[] = {
USBStringDescriptor_LENGTH(3),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('R'),
USBStringDescriptor_UNICODE('A'),
USBStringDescriptor_UNICODE('M'),
};
static const unsigned char altAppStringDescriptor[] = {
USBStringDescriptor_LENGTH(11),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('F'),
USBStringDescriptor_UNICODE('l'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('h'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('('),
USBStringDescriptor_UNICODE('A'),
USBStringDescriptor_UNICODE('p'),
USBStringDescriptor_UNICODE('p'),
USBStringDescriptor_UNICODE(')'),
};
/** List of string descriptors used by the device */
static const unsigned char *usb_strings[] = {
langDesc,
[STR_MANUF] = manufStringDescriptor,
[STR_PROD] = productStringDescriptor,
[STR_CONFIG] = configStringDescriptor,
[_STR_FIRST_ALT] = altRamStringDescriptor,
[_STR_FIRST_ALT+1] = altAppStringDescriptor,
};
#endif #endif
static const USBConfigurationDescriptor *conf_desc_arr[] = { static const USBConfigurationDescriptor *conf_desc_arr[] = {

View File

@@ -217,7 +217,7 @@ void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)
uint8_t req = USBGenericRequest_GetRequest(request); uint8_t req = USBGenericRequest_GetRequest(request);
uint16_t len = USBGenericRequest_GetLength(request); uint16_t len = USBGenericRequest_GetLength(request);
uint16_t val = USBGenericRequest_GetValue(request); uint16_t val = USBGenericRequest_GetValue(request);
int rc, ret; int rc, ret = DFU_RET_NOTHING;
TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r", TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",
USBGenericRequest_GetType(request), USBGenericRequest_GetType(request),
@@ -472,6 +472,14 @@ void USBDFU_SwitchToApp(void)
NVIC_SystemReset(); NVIC_SystemReset();
} }
/* A board can provide a function overriding this, enabling a
* board-specific 'boot into DFU' override, like a specific GPIO that
* needs to be pulled a certain way. */
WEAK int USBDFU_OverrideEnterDFU(void)
{
return 0;
}
void USBDCallbacks_RequestReceived(const USBGenericRequest *request) void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
{ {
USBDFU_DFU_RequestHandler(request); USBDFU_DFU_RequestHandler(request);

View File

@@ -22,6 +22,7 @@
*/ */
#include <board.h> #include <board.h>
#include <assert.h>
#include <core_cm3.h> #include <core_cm3.h>
#include <usb/include/USBD.h> #include <usb/include/USBD.h>
@@ -67,6 +68,26 @@ static void __dfufunc handle_getstate(void)
USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0); USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
} }
static const uint8_t *get_dfu_func_desc(void)
{
USBDDriver *usbdDriver = USBD_GetDriver();
const USBConfigurationDescriptor *cfg_desc;
const USBGenericDescriptor *gen_desc;
if (USBD_IsHighSpeed())
cfg_desc = &usbdDriver->pDescriptors->pHsConfiguration[usbdDriver->cfgnum];
else
cfg_desc = usbdDriver->pDescriptors->pFsConfiguration[usbdDriver->cfgnum];
for (gen_desc = (const USBGenericDescriptor *) cfg_desc;
(const uint8_t *) gen_desc < (const uint8_t *) cfg_desc + cfg_desc->wTotalLength;
gen_desc = (const USBGenericDescriptor *) ((const uint8_t *)gen_desc + gen_desc->bLength)) {
if (gen_desc->bDescriptorType == USB_DT_DFU)
return (const uint8_t *) gen_desc;
}
return NULL;
}
static void TerminateCtrlInWithNull(void *pArg, static void TerminateCtrlInWithNull(void *pArg,
unsigned char status, unsigned char status,
unsigned long int transferred, unsigned long int transferred,
@@ -86,7 +107,7 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
uint8_t req = USBGenericRequest_GetRequest(request); uint8_t req = USBGenericRequest_GetRequest(request);
uint16_t len = USBGenericRequest_GetLength(request); uint16_t len = USBGenericRequest_GetLength(request);
uint16_t val = USBGenericRequest_GetValue(request); uint16_t val = USBGenericRequest_GetValue(request);
int rc, ret; int rc, ret = DFU_RET_NOTHING;
TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r", TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",
USBGenericRequest_GetType(request), USBGenericRequest_GetType(request),
@@ -100,15 +121,18 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
USBGetDescriptorRequest_GetDescriptorType(request) == USB_DT_DFU) { USBGetDescriptorRequest_GetDescriptorType(request) == USB_DT_DFU) {
uint16_t length = sizeof(struct usb_dfu_func_descriptor); uint16_t length = sizeof(struct usb_dfu_func_descriptor);
const USBDeviceDescriptor *pDevice; const USBDeviceDescriptor *pDevice;
const uint8_t *dfu_func_desc = get_dfu_func_desc();
int terminateWithNull; int terminateWithNull;
ASSERT(dfu_func_desc);
if (USBD_IsHighSpeed()) if (USBD_IsHighSpeed())
pDevice = usbdDriver->pDescriptors->pHsDevice; pDevice = usbdDriver->pDescriptors->pHsDevice;
else else
pDevice = usbdDriver->pDescriptors->pFsDevice; pDevice = usbdDriver->pDescriptors->pFsDevice;
terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0); terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
USBD_Write(0, &dfu_cfg_descriptor.func_dfu, length, USBD_Write(0, dfu_func_desc, length,
terminateWithNull ? TerminateCtrlInWithNull : 0, 0); terminateWithNull ? TerminateCtrlInWithNull : 0, 0);
return; return;
} }
@@ -117,7 +141,7 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS || if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS ||
USBGenericRequest_GetRecipient(request) != USBGenericRequest_INTERFACE) { USBGenericRequest_GetRecipient(request) != USBGenericRequest_INTERFACE) {
TRACE_DEBUG("std_ho_usbd "); TRACE_DEBUG("std_ho_usbd ");
USBDDriver_RequestHandler(usbdDriver, request); USBDCallbacks_RequestReceived(request);
return; return;
} }
@@ -192,9 +216,3 @@ void DFURT_SwitchToDFU(void)
* ResetVector of the bootloader */ * ResetVector of the bootloader */
NVIC_SystemReset(); NVIC_SystemReset();
} }
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
{
/* FIXME: integration with CCID control point reqeusts */
USBDFU_Runtime_RequestHandler(request);
}

View File

@@ -1,3 +1,19 @@
/* SIMtrace 2 common board pin definitions
*
* 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
*/
#ifndef _BOARD_ #ifndef _BOARD_
#define _BOARD_ #define _BOARD_
@@ -39,11 +55,11 @@
#define BOARD_MCK 48000000 #define BOARD_MCK 48000000
#define LED_RED PIO_PA17 #define PIO_LED_RED PIO_PA17
#define LED_GREEN PIO_PA18 #define PIO_LED_GREEN PIO_PA18
#define PIN_LED_RED {LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
#define PIN_LED_GREEN {LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN #define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN
#define LED_NUM_RED 0 #define LED_NUM_RED 0
@@ -65,10 +81,14 @@
/** UART0 */ /** UART0 */
/** Console baudrate always using 115200. */ /** Console baudrate always using 115200. */
#define CONSOLE_BAUDRATE 115200 #define CONSOLE_BAUDRATE 115200
/** Usart Hw interface used by the console (UART0). */ /** UART peripheral used by the console (UART0). */
#define CONSOLE_USART UART0 #define CONSOLE_UART UART0
/** Usart Hw ID used by the console (UART0). */ /** UART peripheral ID used by the console (UART0). */
#define CONSOLE_ID ID_UART0 #define CONSOLE_ID ID_UART0
/** UART ISR used by the console (UART0). */
#define CONSOLE_ISR UART0_IrqHandler
/** UART IRQ used by the console (UART0). */
#define CONSOLE_IRQ UART0_IRQn
/** Pins description corresponding to Rxd,Txd, (UART pins) */ /** Pins description corresponding to Rxd,Txd, (UART pins) */
#define CONSOLE_PINS {PINS_UART} #define CONSOLE_PINS {PINS_UART}
@@ -77,39 +97,25 @@
#define BOARD_ISO7816_BASE_USART USART0 #define BOARD_ISO7816_BASE_USART USART0
#define BOARD_ISO7816_ID_USART ID_USART0 #define BOARD_ISO7816_ID_USART ID_USART0
/* USART peripherals for a phone and SIM card setup */
/* USART peripheral connected to the SIM card */
#define USART_SIM USART0 #define USART_SIM USART0
/* ID of USART peripheral connected to the SIM card */
#define ID_USART_SIM ID_USART0 #define ID_USART_SIM ID_USART0
/* Interrupt request ID of USART peripheral connected to the SIM card */
#define IRQ_USART_SIM USART0_IRQn
/* USART peripheral connected to the phone */
#define USART_PHONE USART1 #define USART_PHONE USART1
/* ID of USART peripheral connected to the phone */
#define ID_USART_PHONE ID_USART1 #define ID_USART_PHONE ID_USART1
/* Interrupt request ID of USART peripheral connected to the phone */
#define IRQ_USART_PHONE USART1_IRQn
#define SIM_PWEN PIO_PA5 #define SIM_PWEN PIO_PA5
#define VCC_FWD PIO_PA26 #define VCC_FWD PIO_PA26
//** USB **/
// USB pull-up control pin definition (PA16).
// Default: 1 (USB Pullup deactivated)
#define PIN_USB_PULLUP {1 << 16, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
// Board has UDP controller // Board has UDP controller
#define BOARD_USB_UDP #define BOARD_USB_UDP
// D+ has external pull-up
#define BOARD_USB_PULLUP_EXTERNAL
#define BOARD_USB_NUMENDPOINTS 8
// FIXME: in all other cases return 0?
#define BOARD_USB_ENDPOINTS_MAXPACKETSIZE(i) (((i == 4) || (i == 5))? 512 : 64)
#define BOARD_USB_ENDPOINTS_BANKS(i) (((i == 0) || (i == 3)) ? 1 : 2)
/// USB attributes configuration descriptor (bus or self powered, remote wakeup)
//#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP
//#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_RWAKEUP
#define BOARD_USB_VENDOR SIMTRACE_VENDOR_ID
#define BOARD_USB_PRODUCT SIMTRACE_PRODUCT_ID
#define BOARD_USB_RELEASE 0
#define BOARD_USB_DFU #define BOARD_USB_DFU
#define BOARD_DFU_BOOT_SIZE (16 * 1024) #define BOARD_DFU_BOOT_SIZE (16 * 1024)
@@ -119,4 +125,5 @@
extern void board_exec_dbg_cmd(int ch); extern void board_exec_dbg_cmd(int ch);
extern void board_main_top(void); extern void board_main_top(void);
extern int board_override_enter_dfu(void);
#endif #endif

View File

@@ -26,7 +26,6 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** /**
* \file * \file
* *

View File

@@ -1,3 +1,18 @@
/* 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 #pragma once
int get_board_version_adc(void); int get_board_version_adc(void);
uint32_t adc2uv(uint16_t adc);

View File

@@ -1,72 +1,44 @@
/* ---------------------------------------------------------------------------- /* This program is free software; you can redistribute it and/or modify
* ATMEL Microcontroller Software Support * it under the terms of the GNU General Public License as published by
* ---------------------------------------------------------------------------- * the Free Software Foundation; either version 2 of the License, or
* Copyright (c) 2008, Atmel Corporation * (at your option) any later version.
* *
* All rights reserved. * 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.
* *
* Redistribution and use in source and binary forms, with or without * You should have received a copy of the GNU General Public License
* modification, are permitted provided that the following conditions are met: * along with this program; if not, write to the Free Software
* * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/ */
#pragma once
/** enum led {
* \file LED_RED,
* LED_GREEN,
* \section Purpose _NUM_LED
* };
* Small set of functions for simple and portable LED usage.
*
* \section Usage
*
* -# Configure one or more LEDs using LED_Configure and
* LED_ConfigureAll.
* -# Set, clear and toggle LEDs using LED_Set, LED_Clear and
* LED_Toggle.
*
* LEDs are numbered starting from 0; the number of LEDs depend on the
* board being used. All the functions defined here will compile properly
* regardless of whether the LED is defined or not; they will simply
* return 0 when a LED which does not exist is given as an argument.
* Also, these functions take into account how each LED is connected on to
* board; thus, \ref LED_Set might change the level on the corresponding pin
* to 0 or 1, but it will always light the LED on; same thing for the other
* methods.
*/
#ifndef _LED_ enum led_pattern {
#define _LED_ BLINK_ALWAYS_OFF = 0,
BLINK_ALWAYS_ON = 1,
BLINK_3O_5F = 2,
BLINK_3O_30F = 3,
BLINK_3O_1F_3O_30F = 4,
BLINK_3O_1F_3O_1F_3O_30F= 5,
BLINK_2O_F = 6,
BLINK_200O_F = 7,
BLINK_600O_F = 8,
BLINK_CUSTOM = 9,
BLINK_2F_O,
_NUM_LED_BLINK
};
#include <stdint.h> void led_init(void);
void led_fini(void);
//------------------------------------------------------------------------------ void led_stop(void);
// Global Functions void led_start(void);
//------------------------------------------------------------------------------
extern uint32_t LED_Configure( uint32_t dwLed ) ;
extern uint32_t LED_Set( uint32_t dwLed ) ;
extern uint32_t LED_Clear( uint32_t dwLed ) ;
extern uint32_t LED_Toggle( uint32_t dwLed ) ;
#endif /* #ifndef LED_H */
void led_blink(enum led led, enum led_pattern blink);
enum led_pattern led_get(enum led led);

View File

@@ -1,4 +1,17 @@
/* 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
*/
#ifndef _MANIFEST_H #ifndef _MANIFEST_H
#define _MANIFEST_H #define _MANIFEST_H

View File

@@ -0,0 +1,18 @@
/* 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 sim_switch_use_physical(unsigned int nr, int physical);
int sim_switch_init(void);

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -26,19 +27,17 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#ifndef _UART_CONSOLE_ #ifndef _UART_CONSOLE_
#define _UART_CONSOLE_ #define _UART_CONSOLE_
#include <stdint.h> #include <stdint.h>
extern void UART_Configure( uint32_t dwBaudrate, uint32_t dwMasterClock ) ; extern void UART_Configure( uint32_t dwBaudrate, uint32_t dwMasterClock ) ;
extern void UART_Exit( void ) ;
extern void UART_PutChar( uint8_t uc ) ; extern void UART_PutChar( uint8_t uc ) ;
extern void UART_PutChar_Sync( uint8_t uc ) ;
extern uint32_t UART_GetChar( void ) ; extern uint32_t UART_GetChar( void ) ;
extern uint32_t UART_IsRxReady( void ) ; extern uint32_t UART_IsRxReady( void ) ;
extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) ; extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) ;
extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) ; extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) ;
extern uint32_t UART_GetInteger( uint32_t* pdwValue ) ; extern uint32_t UART_GetInteger( uint32_t* pdwValue ) ;

View File

@@ -2,6 +2,8 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation * Copyright (c) 2010, Atmel Corporation
* Copyright (c) 2017, Harald Welte <laforge@gnumonks.org>
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -132,8 +134,12 @@ static void BootIntoApp(void)
void (*appReset)(void); void (*appReset)(void);
pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE); pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE);
SCB->VTOR = ((unsigned int)(pSrc)) | (0x0 << 7); /* set vector table to application vector table (store at the beginning of the application) */
appReset = pSrc[1]; SCB->VTOR = (unsigned int)(pSrc);
/* set stack pointer to address provided in the beginning of the application (loaded into a register first) */
__asm__ volatile ("MSR msp,%0" : :"r"(*pSrc));
/* start application (by jumping to the reset function which address is stored as second entry of the vector table) */
appReset = (void(*)(void))pSrc[1];
g_dfu->state = DFU_STATE_appIDLE; g_dfu->state = DFU_STATE_appIDLE;
@@ -154,10 +160,9 @@ void ResetException( void )
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) #if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
/* we are before the text segment has been relocated, so g_dfu is if (!USBDFU_OverrideEnterDFU()) {
* not initialized yet */ UART_Exit();
g_dfu = &_g_dfu; __disable_irq();
if (g_dfu->magic != USB_DFU_MAGIC) {
BootIntoApp(); BootIntoApp();
/* Infinite loop */ /* Infinite loop */
while ( 1 ) ; while ( 1 ) ;

View File

@@ -119,10 +119,17 @@ extern WEAK void LowLevelInit( void )
{ {
uint32_t timeout = 0; uint32_t timeout = 0;
/* Configure the Supply Monitor to reset the CPU in case VDDIO is
* lower than 3.0V. As we run the board on 3.3V, any lower voltage
* might be some kind of leakage that creeps in some way, but is not
* the "official" power supply */
SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM |
SUPC_SMMR_SMRSTEN_ENABLE;
/* enable both LED and green LED */ /* enable both LED and green LED */
PIOA->PIO_PER |= LED_RED | LED_GREEN; PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN;
PIOA->PIO_OER |= LED_RED | LED_GREEN; PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN;
PIOA->PIO_CODR |= LED_RED | LED_GREEN; PIOA->PIO_CODR |= PIO_LED_RED | PIO_LED_GREEN;
/* Set 3 FWS for Embedded Flash Access */ /* Set 3 FWS for Embedded Flash Access */
EFC->EEFC_FMR = EEFC_FMR_FWS(3); EFC->EEFC_FMR = EEFC_FMR_FWS(3);
@@ -162,7 +169,7 @@ extern WEAK void LowLevelInit( void )
#endif #endif
/* disable the red LED after main clock initialization */ /* disable the red LED after main clock initialization */
PIOA->PIO_SODR = LED_RED; PIOA->PIO_SODR = PIO_LED_RED;
/* "switch" to main clock as master clock source (should already be the case */ /* "switch" to main clock as master clock source (should already be the case */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;

View File

@@ -1,9 +1,22 @@
/* 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 "board.h"
#include "boardver_adc.h" #include "boardver_adc.h"
/* FIXME: share this with mode_cardemu.c */
#define UV_PER_LSB ((3300 * 1000) / 4096) #define UV_PER_LSB ((3300 * 1000) / 4096)
static uint32_t adc2uv(uint16_t adc) uint32_t adc2uv(uint16_t adc)
{ {
uint32_t uv = (uint32_t) adc * UV_PER_LSB; uint32_t uv = (uint32_t) adc * UV_PER_LSB;
return uv; return uv;
@@ -73,7 +86,7 @@ int get_board_version_adc(void)
/* convert to voltage */ /* convert to voltage */
sample = ADC->ADC_CDR[2]; sample = ADC->ADC_CDR[2];
uv = adc2uv(sample); uv = adc2uv(sample);
TRACE_INFO("VERSION_DET ADC=%u => %u uV\r\n", sample, uv); TRACE_INFO("VERSION_DET ADC=%u => %lu uV\r\n", sample, uv);
/* FIXME: convert to board version based on thresholds */ /* FIXME: convert to board version based on thresholds */

View File

@@ -1,168 +1,296 @@
/* ---------------------------------------------------------------------------- /* LED control
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
* *
* All rights reserved. * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* Redistribution and use in source and binary forms, with or without * This program is free software; you can redistribute it and/or modify
* modification, are permitted provided that the following conditions are met: * 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.
* *
* - Redistributions of source code must retain the above copyright notice, * This program is distributed in the hope that it will be useful,
* this list of conditions and the disclaimer below. * 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.
* *
* Atmel's name may not be used to endorse or promote products derived from * You should have received a copy of the GNU General Public License
* this software without specific prior written permission. * along with this program; if not, write to the Free Software
* * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/ */
#include <stdint.h>
#include <string.h>
#include <assert.h>
/** #include <osmocom/core/timer.h>
* \file
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "board.h" #include "board.h"
#include "utils.h"
/*------------------------------------------------------------------------------ #include "led.h"
* Local Variables
*------------------------------------------------------------------------------*/
#ifdef PINS_LEDS #ifdef PINS_LEDS
static const Pin pinsLeds[] = { PINS_LEDS } ; static const Pin pinsLeds[] = { PINS_LEDS } ;
static const uint32_t numLeds = PIO_LISTSIZE( pinsLeds ) ;
#endif
/*------------------------------------------------------------------------------ static void led_set(enum led led, int on)
* Global Functions
*------------------------------------------------------------------------------*/
/**
* Configures the pin associated with the given LED number. If the LED does
* not exist on the board, the function does nothing.
* \param led Number of the LED to configure.
* \return 1 if the LED exists and has been configured; otherwise 0.
*/
extern uint32_t LED_Configure( uint32_t dwLed )
{
#ifdef PINS_LEDS
// Check that LED exists
if ( dwLed >= numLeds)
{ {
ASSERT(led < PIO_LISTSIZE(pinsLeds));
return 0; if (on)
} PIO_Clear(&pinsLeds[led]);
// Configure LED
return ( PIO_Configure( &pinsLeds[dwLed], 1 ) ) ;
#else
return 0 ;
#endif
}
/**
* Turns the given LED on if it exists; otherwise does nothing.
* \param led Number of the LED to turn on.
* \return 1 if the LED has been turned on; 0 otherwise.
*/
extern uint32_t LED_Set( uint32_t dwLed )
{
#ifdef PINS_LEDS
/* Check if LED exists */
if ( dwLed >= numLeds )
{
return 0 ;
}
/* Turn LED on */
if ( pinsLeds[dwLed].type == PIO_OUTPUT_0 )
{
PIO_Set( &pinsLeds[dwLed] ) ;
}
else else
PIO_Set(&pinsLeds[led]);
}
/* LED blinking code */
/* a single state in a sequence of blinking */
struct blink_state {
/* duration of the state in ms */
uint16_t duration;
/* brightness of LED during the state */
uint8_t on;
} __attribute__((packed));
static const struct blink_state bs_off[] = {
{ 0, 0 }
};
static const struct blink_state bs_on[] = {
{ 0, 1 }
};
static const struct blink_state bs_3on_5off[] = {
{ 300, 1 }, { 500, 0 }
};
static const struct blink_state bs_3on_30off[] = {
{ 300, 1 }, { 3000, 0 }
};
static const struct blink_state bs_3on_1off_3on_30off[] = {
{ 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
};
static const struct blink_state bs_3on_1off_3on_1off_3on_30off[] = {
{ 300, 1 }, { 100, 0 }, { 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
};
static const struct blink_state bs_2on_off[] = {
{ 200, 1 }, { 0, 0 },
};
static const struct blink_state bs_200on_off[] = {
{ 20000, 1 }, { 0, 0 },
};
static const struct blink_state bs_600on_off[] = {
{ 60000, 1 }, { 0, 0 },
};
static const struct blink_state bs_2off_on[] = {
{ 200, 0 }, { 0, 1 },
};
/* a blink pattern is an array of blink_states */
struct blink_pattern {
const struct blink_state *states;
uint16_t size;
};
/* compiled-in default blinking patterns */
static const struct blink_pattern patterns[] = {
[BLINK_ALWAYS_OFF] = {
.states = bs_off,
.size = ARRAY_SIZE(bs_off),
},
[BLINK_ALWAYS_ON] = {
.states = bs_on,
.size = ARRAY_SIZE(bs_on),
},
[BLINK_3O_5F] = {
.states = bs_3on_5off,
.size = ARRAY_SIZE(bs_3on_5off),
},
[BLINK_3O_30F] = {
.states = bs_3on_30off,
.size = ARRAY_SIZE(bs_3on_30off),
},
[BLINK_3O_1F_3O_30F] = {
.states = bs_3on_1off_3on_30off,
.size = ARRAY_SIZE(bs_3on_1off_3on_30off),
},
[BLINK_3O_1F_3O_1F_3O_30F] = {
.states = bs_3on_1off_3on_1off_3on_30off,
.size = ARRAY_SIZE(bs_3on_1off_3on_1off_3on_30off),
},
[BLINK_2O_F] = {
.states = bs_2on_off,
.size = ARRAY_SIZE(bs_2on_off),
},
[BLINK_200O_F] = {
.states = bs_200on_off,
.size = ARRAY_SIZE(bs_200on_off),
},
[BLINK_600O_F] = {
.states = bs_600on_off,
.size = ARRAY_SIZE(bs_600on_off),
},
[BLINK_2F_O] = {
.states = bs_2off_on,
.size = ARRAY_SIZE(bs_2off_on),
},
};
struct led_state {
/* which led are we handling */
enum led led;
/* timer */
struct osmo_timer_list timer;
/* pointer and size of blink array */
const struct blink_pattern *pattern;
unsigned int cur_state;
unsigned int illuminated;
/* static allocated space for custom blinking pattern */
struct blink_pattern pattern_cust;
struct blink_state blink_cust[10];
};
static unsigned int cur_state_inc(struct led_state *ls)
{ {
PIO_Clear( &pinsLeds[dwLed] ) ; ls->cur_state = (ls->cur_state + 1) % ls->pattern->size;
return ls->cur_state;
} }
return 1 ; static const struct blink_state *
#else next_blink_state(struct led_state *ls)
return 0 ; {
#endif return &ls->pattern->states[cur_state_inc(ls)];
} }
/** /* apply the next state to the LED */
* Turns a LED off. static void apply_blinkstate(struct led_state *ls,
* const struct blink_state *bs)
* \param led Number of the LED to turn off. {
* \return 1 if the LED has been turned off; 0 otherwise. led_set(ls->led, bs->on);
*/ ls->illuminated = bs->on;
extern uint32_t LED_Clear( uint32_t dwLed )
/* re-schedule the timer */
if (bs->duration) {
uint32_t us = bs->duration * 1000;
osmo_timer_schedule(&ls->timer, us / 1000000, us % 1000000);
}
}
static void blink_tmr_cb(void *data)
{
struct led_state *ls = data;
const struct blink_state *next_bs = next_blink_state(ls);
/* apply the next state to the LED */
apply_blinkstate(ls, next_bs);
}
static struct led_state led_state[] = {
[LED_RED] = {
.led = LED_RED,
.timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_RED],
},
[LED_GREEN] = {
.led = LED_GREEN,
.timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_GREEN],
},
};
#endif /* PINS_LEDS */
void led_blink(enum led led, enum led_pattern blink)
{ {
#ifdef PINS_LEDS #ifdef PINS_LEDS
/* Check if LED exists */ struct led_state *ls;
if ( dwLed >= numLeds )
{ if (led >= ARRAY_SIZE(led_state))
return 0 ; return;
ls = &led_state[led];
/* stop previous blinking, if any */
osmo_timer_del(&ls->timer);
led_set(led, 0);
ls->illuminated = 0;
ls->pattern = NULL;
ls->cur_state = 0;
switch (blink) {
case BLINK_CUSTOM:
ls->pattern = &ls->pattern_cust;
break;
default:
if (blink >= ARRAY_SIZE(patterns))
return;
ls->pattern = &patterns[blink];
break;
} }
/* Turn LED off */ if (ls->pattern && ls->pattern->size > 0)
if ( pinsLeds[dwLed].type == PIO_OUTPUT_0 ) apply_blinkstate(ls, &ls->pattern->states[0]);
{
PIO_Clear( &pinsLeds[dwLed] ) ;
}
else
{
PIO_Set( &pinsLeds[dwLed] ) ;
}
return 1 ;
#else
return 0 ;
#endif #endif
} }
/** enum led_pattern led_get(enum led led)
* Toggles the current state of a LED.
*
* \param led Number of the LED to toggle.
* \return 1 if the LED has been toggled; otherwise 0.
*/
extern uint32_t LED_Toggle( uint32_t dwLed )
{ {
#ifdef PINS_LEDS #ifdef PINS_LEDS
/* Check if LED exists */ struct led_state *ls;
if ( dwLed >= numLeds ) unsigned int i;
{
return 0 ; if (led >= ARRAY_SIZE(led_state))
return -1;
ls = &led_state[led];
if (ls->pattern == &ls->pattern_cust)
return BLINK_CUSTOM;
for (i = 0; i < ARRAY_SIZE(patterns); i++) {
if (ls->pattern == &patterns[i])
return i;
}
#endif
/* default case, shouldn't be reached */
return -1;
} }
/* Toggle LED */ void led_start(void)
if ( PIO_GetOutputDataStatus( &pinsLeds[dwLed] ) )
{ {
PIO_Clear( &pinsLeds[dwLed] ) ; led_set(LED_GREEN, led_state[LED_GREEN].illuminated);
} led_set(LED_RED, led_state[LED_RED].illuminated);
else
{
PIO_Set( &pinsLeds[dwLed] ) ;
} }
return 1 ; void led_stop(void)
#else {
return 0 ; led_set(LED_GREEN, 0);
led_set(LED_RED, 0);
}
void led_init(void)
{
#ifdef PINS_LEDS
PIO_Configure(pinsLeds, PIO_LISTSIZE(pinsLeds));
led_set(LED_GREEN, 0);
led_set(LED_RED, 0);
#endif #endif
} }
void led_fini(void)
{
#ifdef PINS_LEDS
/* we don't actually need to do this, but just in case... */
osmo_timer_del(&led_state[LED_RED].timer);
osmo_timer_del(&led_state[LED_GREEN].timer);
led_set(LED_GREEN, 0);
led_set(LED_RED, 0);
#endif
}

View File

@@ -1,4 +1,17 @@
/* 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 "manifest.h" #include "manifest.h"
const char *manifest_application = APPLICATION; const char *manifest_application = APPLICATION;

View File

@@ -0,0 +1,90 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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"
#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;
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) {
#ifdef PIN_SIM_SWITCH1
case 0:
pin = &pin_conn_usim1;
led = LED_USIM1;
break;
#endif
#ifdef PIN_SIM_SWITCH2
case 1:
pin = &pin_conn_usim2;
led = LED_USIM2;
break;
#endif
default:
TRACE_ERROR("Invalid SIM%u\n\r", nr);
return -1;
}
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Clear(pin);
led_blink(led, BLINK_ALWAYS_ON);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Set(pin);
led_blink(led, BLINK_ALWAYS_OFF);
}
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
initialized = 1;
return num_switch;
}

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -43,6 +44,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include "ringbuffer.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Definitions * Definitions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@@ -53,6 +56,8 @@
/** Is Console Initialized. */ /** Is Console Initialized. */
static uint8_t _ucIsConsoleInitialized=0; static uint8_t _ucIsConsoleInitialized=0;
/** Ring buffer to queue data to be sent */
static ringbuf uart_tx_buffer;
/** /**
* \brief Configures an USART peripheral with the specified parameters. * \brief Configures an USART peripheral with the specified parameters.
@@ -63,7 +68,7 @@ static uint8_t _ucIsConsoleInitialized=0 ;
extern void UART_Configure( uint32_t baudrate, uint32_t masterClock) extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
{ {
const Pin pPins[] = CONSOLE_PINS; const Pin pPins[] = CONSOLE_PINS;
Uart *pUart = CONSOLE_USART; Uart *pUart = CONSOLE_UART;
/* Configure PIO */ /* Configure PIO */
PIO_Configure(pPins, PIO_LISTSIZE(pPins)); PIO_Configure(pPins, PIO_LISTSIZE(pPins));
@@ -85,33 +90,94 @@ extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
/* Disable PDC channel */ /* Disable PDC channel */
pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
/* Reset transmit ring buffer */
rbuf_reset(&uart_tx_buffer);
/* Enable TX interrupts */
pUart->UART_IER = UART_IER_TXRDY;
NVIC_EnableIRQ(CONSOLE_IRQ);
/* Enable receiver and transmitter */ /* Enable receiver and transmitter */
pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN; pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
/* Remember the configuration is complete */
_ucIsConsoleInitialized=1 ; _ucIsConsoleInitialized=1 ;
} }
/**
* \brief Disables the USART peripheral and related IRQ
*/
void UART_Exit(void)
{
if (!_ucIsConsoleInitialized) {
return;
}
Uart *pUart = CONSOLE_UART;
pUart->UART_IDR = UART_IDR_TXRDY;
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA;
PMC->PMC_PCDR0 = 1 << CONSOLE_ID;
NVIC_DisableIRQ(CONSOLE_IRQ);
}
/** Interrupt Service routine to transmit queued data */
void CONSOLE_ISR(void)
{
Uart *uart = CONSOLE_UART;
if (uart->UART_SR & UART_SR_TXRDY) {
if (!rbuf_is_empty(&uart_tx_buffer)) {
uart->UART_THR = rbuf_read(&uart_tx_buffer);
} else {
uart->UART_IDR = UART_IER_TXRDY;
}
}
}
/** /**
* \brief Outputs a character on the UART line. * \brief Outputs a character on the UART line.
* *
* \note This function is synchronous (i.e. uses polling). * \note This function is asynchronous (i.e. uses a buffer and interrupt to complete the transfer).
* \param c Character to send. * \param c Character to send.
*/ */
extern void UART_PutChar( uint8_t c ) void UART_PutChar( uint8_t uc )
{ {
Uart *pUart=CONSOLE_USART ; Uart *pUart = CONSOLE_UART ;
/* Initialize console is not already done */
if ( !_ucIsConsoleInitialized ) if ( !_ucIsConsoleInitialized )
{ {
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
} }
/* Wait for the transmitter to be ready */ if (!rbuf_is_full(&uart_tx_buffer)) {
while ( (pUart->UART_SR & UART_SR_TXEMPTY) == 0 ) ; rbuf_write(&uart_tx_buffer, uc);
if (!(pUart->UART_IMR & UART_IMR_TXRDY)) {
pUart->UART_IER = UART_IER_TXRDY;
CONSOLE_ISR();
}
}
}
/* Send character */ /**
pUart->UART_THR=c ; * \brief Outputs a character on the UART line.
*
* \note This function is synchronous (i.e. uses polling and blocks until the transfer is complete).
* \param c Character to send.
*/
void UART_PutChar_Sync( uint8_t uc )
{
Uart *pUart = CONSOLE_UART ;
/* Initialize console is not already done */
if ( !_ucIsConsoleInitialized )
{
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
}
while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to be empty */
pUart->UART_THR = uc; /* Send data to UART peripheral */
while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to transferred to shift register */
while (!(pUart->UART_SR & UART_SR_TXEMPTY)); /* Wait for transfer shift register to be empty (i.e. transfer is complete) */
} }
/** /**
@@ -122,14 +188,15 @@ extern void UART_PutChar( uint8_t c )
*/ */
extern uint32_t UART_GetChar( void ) extern uint32_t UART_GetChar( void )
{ {
Uart *pUart=CONSOLE_USART ; Uart *pUart = CONSOLE_UART ;
if ( !_ucIsConsoleInitialized ) if ( !_ucIsConsoleInitialized )
{ {
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
} }
while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 ) ; while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
WDT_Restart(WDT);
return pUart->UART_RHR ; return pUart->UART_RHR ;
} }
@@ -141,7 +208,7 @@ extern uint32_t UART_GetChar( void )
*/ */
extern uint32_t UART_IsRxReady( void ) extern uint32_t UART_IsRxReady( void )
{ {
Uart *pUart=CONSOLE_USART ; Uart *pUart = CONSOLE_UART;
if ( !_ucIsConsoleInitialized ) if ( !_ucIsConsoleInitialized )
{ {
@@ -281,6 +348,7 @@ extern uint32_t UART_GetInteger( uint32_t* pdwValue )
return 0 ; return 0 ;
} }
} }
WDT_Restart(WDT);
} }
} }

View File

@@ -1,5 +1,24 @@
/* OWHW board definition
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 #pragma once
#include "board_common.h" #include "board_common.h"
#include "simtrace_usb.h"
/** Name of the board */ /** Name of the board */
#define BOARD_NAME "OWHW" #define BOARD_NAME "OWHW"
@@ -41,10 +60,12 @@
#define PINS_CARDSIM { PIN_SET_USIM1_PRES, PIN_SET_USIM2_PRES } #define PINS_CARDSIM { PIN_SET_USIM1_PRES, PIN_SET_USIM2_PRES }
#define SIMTRACE_VENDOR_ID 0x1d50 #define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP
#define SIMTRACE_PRODUCT_ID 0x60e3 /* FIXME */
#define USB_VENDOR_ID SIMTRACE_VENDOR_ID #define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
#define USB_PRODUCT_ID SIMTRACE_PRODUCT_ID #define BOARD_USB_PRODUCT_ID USB_PRODUCT_OWHW_SAM3
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_OWHW_SAM3_DFU
#define BOARD_USB_RELEASE 0x010
#define CARDEMU_SECOND_UART #define CARDEMU_SECOND_UART
/* Disable VCC/ADC detection, as OWHWv2 has no ADCVREF */ /* Disable VCC/ADC detection, as OWHWv2 has no ADCVREF */

View File

@@ -1,5 +1,6 @@
/* Card simulator specific functions */ /* Card simulator specific functions
/* (C) 2015 by Harald Welte <hwelte@hmw-consulting.de> *
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -13,8 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
*/ */
#include "chip.h" #include "chip.h"
@@ -36,5 +36,5 @@ void cardsim_set_simpres(uint8_t slot, int present)
void cardsim_gpio_init(void) void cardsim_gpio_init(void)
{ {
PIO_Configure(&pins_cardsim, ARRAY_SIZE(pins_cardsim)); PIO_Configure(pins_cardsim, ARRAY_SIZE(pins_cardsim));
} }

View File

@@ -1,5 +1,27 @@
/* sysmocom quad-modem sysmoQMOD board definition
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 #pragma once
#include "board_common.h" #include "board_common.h"
#include "simtrace_usb.h"
#define LED_USIM1 LED_GREEN
#define LED_USIM2 LED_RED
/** Name of the board */ /** Name of the board */
#define BOARD_NAME "QMOD" #define BOARD_NAME "QMOD"
@@ -28,19 +50,20 @@
#define PIN_USIM1_CLK_TC {PIO_PA29, 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 PINS_TC_USIM1 PIN_USIM1_IO_TC, PIN_USIM1_CLK_TC
#define PIN_SET_USIM1_PRES {PIO_PA12, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} #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_USIM1_VCC {PIO_PB3, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT}
#define PIN_SET_USIM2_PRES {PIO_PA14, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define PIN_USIM2_nRST {PIO_PA7, PIOA, ID_PIOA, 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 PIN_USIM2_VCC {PIO_PB2, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT}
#define PINS_USIM1 PINS_TC_USIM1, PINS_ISO7816_USIM1, PIN_USIM1_nRST, PIN_SET_USIM1_PRES #define PINS_USIM1 PINS_TC_USIM1, PINS_ISO7816_USIM1, PIN_USIM1_nRST
#define PINS_USIM2 PINS_TC_USIM2, PINS_ISO7816_USIM2, PIN_USIM2_nRST, PIN_SET_USIM2_PRES #define PINS_USIM2 PINS_TC_USIM2, PINS_ISO7816_USIM2, PIN_USIM2_nRST
#define PINS_CARDSIM { PIN_SET_USIM1_PRES, PIN_SET_USIM2_PRES } /* from v3 and onwards only (!) */
#define PIN_DET_USIM1_PRES {PIO_PA12, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEGLITCH | PIO_IT_EDGE}
#define PIN_DET_USIM2_PRES {PIO_PA8, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEGLITCH | PIO_IT_EDGE}
/* only in v2 and lower (!) */
#define PIN_PRTPWR_OVERRIDE {PIO_PA8, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_PRTPWR_OVERRIDE {PIO_PA8, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* inputs reading the WWAN LED level */ /* inputs reading the WWAN LED level */
@@ -55,10 +78,16 @@
#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT} #define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT}
#define SIMTRACE_VENDOR_ID 0x1d50 /* GPIO towards SPDT switches between real SIM and SAM3 */
#define SIMTRACE_PRODUCT_ID 0x60e3 /* FIXME */ #define PIN_SIM_SWITCH1 {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define USB_VENDOR_ID SIMTRACE_VENDOR_ID #define PIN_SIM_SWITCH2 {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define USB_PRODUCT_ID SIMTRACE_PRODUCT_ID
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_QMOD_SAM3
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_QMOD_SAM3_DFU
#define BOARD_USB_RELEASE 0x010
#define CARDEMU_SECOND_UART #define CARDEMU_SECOND_UART
#define DETECT_VCC_BY_ADC #define DETECT_VCC_BY_ADC

View File

@@ -0,0 +1,22 @@
/* card presence utilities
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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);

View File

@@ -1,3 +1,19 @@
/* I2C EEPROM memory read and write utilities
*
* 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 #pragma once
void i2c_pin_init(void); void i2c_pin_init(void);

View File

@@ -1,3 +1,19 @@
/* 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 #pragma once
int wwan_led_active(int wwan); int wwan_led_active(int wwan);

View File

@@ -1,4 +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 #pragma once
int wwan_perst_do_reset(int modem_nr); 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); int wwan_perst_init(void);

View File

@@ -1,14 +1,31 @@
/* Quad-modem speciic application code */ /* sysmocom quad-modem sysmoQMOD application code
/* (C) 2016-2016 by Harald Welte <laforge@gnumonks.org> */ *
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "req_ctx.h"
#include "wwan_led.h" #include "wwan_led.h"
#include "wwan_perst.h" #include "wwan_perst.h"
#include "sim_switch.h"
#include "boardver_adc.h" #include "boardver_adc.h"
#include "osmocom/core/timer.h" #include "card_pres.h"
#include <osmocom/core/timer.h>
#include "usb_buf.h"
static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE; static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE;
static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
@@ -16,6 +33,8 @@ 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_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_peer_erase = {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
/* array of generated USB Strings */
extern unsigned char *usb_strings[];
static int qmod_sam3_is_12(void) static int qmod_sam3_is_12(void)
{ {
@@ -26,7 +45,11 @@ static int qmod_sam3_is_12(void)
} }
const unsigned char __eeprom_bin[256] = { const unsigned char __eeprom_bin[256] = {
0x23, 0x42, 0x17, 0x25, 0x00, 0x00, 0x9b, 0x20, 0x01, 0x00, 0x00, 0x00, 0x32, 0x32, 0x32, 0x32, /* 0x00 - 0x0f */ USB_VENDOR_OPENMOKO & 0xff,
USB_VENDOR_OPENMOKO >> 8,
USB_PRODUCT_QMOD_HUB & 0xff,
USB_PRODUCT_QMOD_HUB >> 8,
0x00, 0x00, 0x9b, 0x20, 0x09, 0x00, 0x00, 0x00, 0x32, 0x32, 0x32, 0x32, /* 0x00 - 0x0f */
0x32, 0x04, 0x09, 0x18, 0x0d, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x6f, 0x00, /* 0x10 - 0x1f */ 0x32, 0x04, 0x09, 0x18, 0x0d, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x6f, 0x00, /* 0x10 - 0x1f */
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x73, 0x00, 0x2e, 0x00, /* 0x20 - 0x2f */ 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x73, 0x00, 0x2e, 0x00, /* 0x20 - 0x2f */
0x66, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x47, 0x00, /* 0x30 - 0x3f */ 0x66, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x47, 0x00, /* 0x30 - 0x3f */
@@ -47,33 +70,29 @@ const unsigned char __eeprom_bin[256] = {
#include "i2c.h" #include "i2c.h"
static int write_hub_eeprom(void) static int write_hub_eeprom(void)
{ {
const unsigned int __eeprom_bin_len = 256;
int i; int i;
/* wait */ /* wait */
volatile int v; mdelay(100);
/* 440ns per cycle here */
for (i = 0; i < 1000000; i++) {
v = 0;
}
TRACE_INFO("Writing EEPROM...\r\n"); TRACE_INFO("Writing EEPROM...\n\r");
/* write the EEPROM once */ /* write the EEPROM once */
for (i = 0; i < 256; i++) { for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
int rc = eeprom_write_byte(0x50, i, __eeprom_bin[i]); int rc = eeprom_write_byte(0x50, i, __eeprom_bin[i]);
/* if the result was negative, repeat that write */ if (rc < 0) {
if (rc < 0) TRACE_ERROR("Writing EEPROM failed at byte %u: 0x%02x\n\r",
i--; i, __eeprom_bin[i]);
return 1;
}
} }
/* then pursue re-reading it again and again */ /* then pursue re-reading it again and again */
TRACE_INFO("Verifying EEPROM...\r\n"); TRACE_INFO("Verifying EEPROM...\n\r");
for (i = 0; i < 256; i++) { for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
int byte = eeprom_read_byte(0x50, i); int byte = eeprom_read_byte(0x50, i);
TRACE_INFO("0x%02x: %02x\r\n", i, byte); TRACE_INFO("0x%02x: %02x\n\r", i, byte);
if (byte != __eeprom_bin[i]) if (byte != __eeprom_bin[i])
TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\r\n", TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r",
i, __eeprom_bin[i], byte); i, __eeprom_bin[i], byte);
} }
@@ -83,119 +102,239 @@ static int write_hub_eeprom(void)
return 0; return 0;
} }
/* returns '1' in case we should break any endless loop */ static int erase_hub_eeprom(void)
void board_exec_dbg_cmd(int ch) {
int i;
/* wait */
mdelay(100);
TRACE_INFO("Erasing EEPROM...\n\r");
/* write the EEPROM once */
for (i = 0; i < 256; i++) {
int rc = eeprom_write_byte(0x50, i, 0xff);
if (rc < 0) {
TRACE_ERROR("Erasing EEPROM failed at byte %u: 0x%02x\n\r",
i, __eeprom_bin[i]);
return 1;
}
}
return 0;
}
static void board_exec_dbg_cmd_st12only(int ch)
{ {
uint32_t addr, val; uint32_t addr, val;
/* functions below only work on primary (ST12) */
if (!qmod_sam3_is_12())
return;
switch (ch) { switch (ch) {
case '?':
printf("\t?\thelp\r\n");
printf("\tE\tprogram EEPROM\r\n");
printf("\tR\treset SAM3\r\n");
printf("\tO\tEnable PRTPWR_OVERRIDE\r\n");
printf("\to\tDisable PRTPWR_OVERRIDE\r\n");
printf("\tH\tRelease HUB RESET (high)\r\n");
printf("\th\tAssert HUB RESET (low)\r\n");
printf("\tw\tWrite single byte in EEPROM\r\n");
printf("\tr\tRead single byte from EEPROM\r\n");
printf("\tX\tRelease peer SAM3 from reset\r\n");
printf("\tx\tAssert peer SAM3 reset\r\n");
printf("\tY\tRelease peer SAM3 ERASE signal\r\n");
printf("\ty\tAssert peer SAM3 ERASE signal\r\n");
printf("\tU\tProceed to USB Initialization\r\n");
printf("\t1\tGenerate 1ms reset pulse on WWAN1\r\n");
printf("\t2\tGenerate 1ms reset pulse on WWAN2\r\n");
break;
case 'E': case 'E':
write_hub_eeprom(); write_hub_eeprom();
break; break;
case 'R': case 'e':
printf("Asking NVIC to reset us\r\n"); erase_hub_eeprom();
NVIC_SystemReset();
break; break;
case 'O': case 'O':
printf("Setting PRTPWR_OVERRIDE\r\n"); printf("Setting PRTPWR_OVERRIDE\n\r");
PIO_Set(&pin_hubpwr_override); PIO_Set(&pin_hubpwr_override);
break; break;
case 'o': case 'o':
printf("Clearing PRTPWR_OVERRIDE\r\n"); printf("Clearing PRTPWR_OVERRIDE\n\r");
PIO_Clear(&pin_hubpwr_override); PIO_Clear(&pin_hubpwr_override);
break; break;
case 'H': case 'H':
printf("Clearing _HUB_RESET -> HUB_RESET high (inactive)\r\n"); printf("Clearing _HUB_RESET -> HUB_RESET high (inactive)\n\r");
PIO_Clear(&pin_hub_rst); PIO_Clear(&pin_hub_rst);
break; break;
case 'h': case 'h':
/* high level drives transistor -> HUB_RESET low */ /* high level drives transistor -> HUB_RESET low */
printf("Asserting _HUB_RESET -> HUB_RESET low (active)\r\n"); printf("Asserting _HUB_RESET -> HUB_RESET low (active)\n\r");
PIO_Set(&pin_hub_rst); PIO_Set(&pin_hub_rst);
break; break;
case 'w': case 'w':
if (PIO_GetOutputDataStatus(&pin_hub_rst) == 0) if (PIO_GetOutputDataStatus(&pin_hub_rst) == 0)
printf("WARNING: attempting EEPROM access while HUB not in reset\r\n"); printf("WARNING: attempting EEPROM access while HUB not in reset\n\r");
printf("Please enter EEPROM offset:\r\n"); printf("Please enter EEPROM offset:\n\r");
UART_GetIntegerMinMax(&addr, 0, 255); UART_GetIntegerMinMax(&addr, 0, 255);
printf("Please enter EEPROM value:\r\n"); printf("Please enter EEPROM value:\n\r");
UART_GetIntegerMinMax(&val, 0, 255); UART_GetIntegerMinMax(&val, 0, 255);
printf("Writing value 0x%02x to EEPROM offset 0x%02x\r\n", val, addr); printf("Writing value 0x%02lx to EEPROM offset 0x%02lx\n\r", val, addr);
eeprom_write_byte(0x50, addr, val); eeprom_write_byte(0x50, addr, val);
break; break;
case 'r': case 'r':
printf("Please enter EEPROM offset:\r\n"); printf("Please enter EEPROM offset:\n\r");
UART_GetIntegerMinMax(&addr, 0, 255); UART_GetIntegerMinMax(&addr, 0, 255);
printf("EEPROM[0x%02x] = 0x%02x\r\n", addr, eeprom_read_byte(0x50, addr)); printf("EEPROM[0x%02lx] = 0x%02x\n\r", addr, eeprom_read_byte(0x50, addr));
break;
default:
printf("Unknown command '%c'\n\r", ch);
break;
}
}
/* 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");
if (qmod_sam3_is_12()) {
printf("\tE\tprogram EEPROM\n\r");
printf("\te\tErase EEPROM\n\r");
printf("\tO\tEnable PRTPWR_OVERRIDE\n\r");
printf("\to\tDisable PRTPWR_OVERRIDE\n\r");
printf("\tH\tRelease HUB RESET (high)\n\r");
printf("\th\tAssert HUB RESET (low)\n\r");
printf("\tw\tWrite single byte in EEPROM\n\r");
printf("\tr\tRead single byte from EEPROM\n\r");
}
printf("\tX\tRelease peer SAM3 from reset\n\r");
printf("\tx\tAssert peer SAM3 reset\n\r");
printf("\tY\tRelease peer SAM3 ERASE signal\n\r");
printf("\ty\tAssert peer SAM3 ERASE signal\n\r");
printf("\tU\tProceed to USB Initialization\n\r");
printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r");
printf("\t2\tGenerate 1ms reset pulse on WWAN2\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
NVIC_SystemReset();
break; break;
case 'X': case 'X':
printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\r\n"); printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r");
PIO_Clear(&pin_peer_rst); PIO_Clear(&pin_peer_rst);
break; break;
case 'x': case 'x':
printf("Setting _SIMTRACExx_RST -> SIMTRACExx_RST low (active)\r\n"); printf("Setting _SIMTRACExx_RST -> SIMTRACExx_RST low (active)\n\r");
PIO_Set(&pin_peer_rst); PIO_Set(&pin_peer_rst);
break; break;
case 'Y': case 'Y':
printf("Clearing SIMTRACExx_ERASE (inactive)\r\n"); printf("Clearing SIMTRACExx_ERASE (inactive)\n\r");
PIO_Clear(&pin_peer_erase); PIO_Clear(&pin_peer_erase);
break; break;
case 'y': case 'y':
printf("Seetting SIMTRACExx_ERASE (active)\r\n"); printf("Seetting SIMTRACExx_ERASE (active)\n\r");
PIO_Set(&pin_peer_erase); PIO_Set(&pin_peer_erase);
break; break;
case '1': case '1':
printf("Resetting Modem 1 (of this SAM3)\r\n"); printf("Resetting Modem 1 (of this SAM3)\n\r");
wwan_perst_do_reset(1); wwan_perst_do_reset_pulse(0, 300);
break; break;
case '2': case '2':
printf("Resetting Modem 2 (of this SAM3)\r\n"); printf("Resetting Modem 2 (of this SAM3)\n\r");
wwan_perst_do_reset(2); wwan_perst_do_reset_pulse(1, 300);
break;
case '!':
sim_switch_use_physical(0, 0);
break;
case '@':
sim_switch_use_physical(0, 0);
break; break;
default: default:
printf("Unknown command '%c'\r\n", ch); if (!qmod_sam3_is_12())
printf("Unknown command '%c'\n\r", ch);
else
board_exec_dbg_cmd_st12only(ch);
break; break;
} }
} }
void board_main_top(void) void board_main_top(void)
{ {
#ifndef APPLICATION_dfu
usb_buf_init();
wwan_led_init(); wwan_led_init();
wwan_perst_init(); wwan_perst_init();
sim_switch_init();
#endif
/* make sure we can detect whether running in ST12 or ST34 */
PIO_Configure(&pin_1234_detect, 1);
if (qmod_sam3_is_12()) {
/* set PIN_PRTPWR_OVERRIDE to output-low to avoid the internal /* set PIN_PRTPWR_OVERRIDE to output-low to avoid the internal
* pull-up on the input to keep SIMTRACE12 alive */ * pull-up on the input to keep SIMTRACE12 alive */
PIO_Configure(&pin_hubpwr_override, 1); PIO_Configure(&pin_hubpwr_override, 1);
PIO_Configure(&pin_hub_rst, 1); PIO_Configure(&pin_hub_rst, 1);
PIO_Configure(&pin_1234_detect, 1); }
PIO_Configure(&pin_peer_rst, 1); PIO_Configure(&pin_peer_rst, 1);
PIO_Configure(&pin_peer_erase, 1); PIO_Configure(&pin_peer_erase, 1);
#ifndef APPLICATION_dfu
i2c_pin_init(); i2c_pin_init();
#endif
if (qmod_sam3_is_12()) { if (qmod_sam3_is_12()) {
TRACE_INFO("Detected Quad-Modem ST12\r\n"); TRACE_INFO("Detected Quad-Modem ST12\n\r");
} else { } else {
TRACE_INFO("Detected Quad-Modem ST34\r\n"); TRACE_INFO("Detected Quad-Modem ST34\n\r");
/* make sure we use the second set of USB Strings
* calling the interfaces "Modem 3" and "Modem 4" rather
* than 1+2 */
usb_strings[7] = usb_strings[9];
usb_strings[8] = usb_strings[10];
} }
/* Obtain the circuit board version (currently just prints voltage */ /* Obtain the circuit board version (currently just prints voltage */
get_board_version_adc(); get_board_version_adc();
#ifndef APPLICATION_dfu
/* Initialize checking for card insert/remove events */
card_present_init();
#endif
}
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;
} }

View File

@@ -0,0 +1,76 @@
/* card presence utilities
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 <osmocom/core/timer.h>
#include "board.h"
#include "utils.h"
#include "card_pres.h"
#define NUM_CARDPRES 2
#define TIMER_INTERVAL_MS 500
static const Pin pin_cardpres[NUM_CARDPRES] = { PIN_DET_USIM1_PRES, PIN_DET_USIM2_PRES };
static int last_state[NUM_CARDPRES] = { -1, -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];
/* Card present signals are low-active, as we have a switch
* against GND and an internal-pull-up in the SAM3 */
present = PIO_Get(pin) ? 0 : 1;
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;
}

View File

@@ -1,3 +1,19 @@
/* I2C EEPROM memory read and write utilities
*
* 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 "board.h"
#include <stdbool.h> #include <stdbool.h>
@@ -157,6 +173,8 @@ int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
{ {
bool nack; bool nack;
WDT_Restart(WDT);
/* Write slave address */ /* Write slave address */
nack = i2c_write_byte(true, false, slave << 1); nack = i2c_write_byte(true, false, slave << 1);
if (nack) if (nack)
@@ -167,6 +185,8 @@ int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
nack = i2c_write_byte(false, true, byte); nack = i2c_write_byte(false, true, byte);
if (nack) if (nack)
goto out_stop; goto out_stop;
/* Wait tWR time to ensure EEPROM is writing correctly (tWR = 5 ms for AT24C02) */
mdelay(5);
out_stop: out_stop:
i2c_stop_cond(); i2c_stop_cond();
@@ -180,6 +200,8 @@ int eeprom_read_byte(uint8_t slave, uint8_t addr)
{ {
bool nack; bool nack;
WDT_Restart(WDT);
/* dummy write cycle */ /* dummy write cycle */
nack = i2c_write_byte(true, false, slave << 1); nack = i2c_write_byte(true, false, slave << 1);
if (nack) if (nack)

View File

@@ -1,11 +1,24 @@
/* Code to read/track the status of the WWAN LEDs of attached modems /* Code to read/track the status of the WWAN LEDs of attached modems
* *
* Depending on the board this is running on, it might be possible * 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 * 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 * the cellular modem. If the board supports this, it sets the
* PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file. * PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file.
*/ */
#include "board.h" #include "board.h"
#include "wwan_led.h" #include "wwan_led.h"
@@ -14,9 +27,9 @@ static const Pin pin_wwan1 = PIN_WWAN1;
static void wwan1_irqhandler(const Pin *pPin) static void wwan1_irqhandler(const Pin *pPin)
{ {
int active = wwan_led_active(1); int active = wwan_led_active(0);
TRACE_INFO("WWAN1 LED %u\r\n", active); TRACE_INFO("0: WWAN LED %u\r\n", active);
/* TODO: notify host via USB */ /* TODO: notify host via USB */
} }
@@ -27,8 +40,8 @@ static const Pin pin_wwan2 = PIN_WWAN2;
static void wwan2_irqhandler(const Pin *pPin) static void wwan2_irqhandler(const Pin *pPin)
{ {
int active = wwan_led_active(2); int active = wwan_led_active(1);
TRACE_INFO("WWAN2 LED %u\r\n", active); TRACE_INFO("1: WWAN LED %u\r\n", active);
/* TODO: notify host via USB */ /* TODO: notify host via USB */
} }
@@ -42,12 +55,12 @@ int wwan_led_active(int wwan)
switch (wwan) { switch (wwan) {
#ifdef PIN_WWAN1 #ifdef PIN_WWAN1
case 1: case 0:
pin = &pin_wwan1; pin = &pin_wwan1;
break; break;
#endif #endif
#ifdef PIN_WWAN2 #ifdef PIN_WWAN2
case 2: case 1:
pin = &pin_wwan2; pin = &pin_wwan2;
break; break;
#endif #endif
@@ -55,7 +68,7 @@ int wwan_led_active(int wwan)
return -1; return -1;
} }
active = PIO_Get(&pin_wwan1) ? 0 : 1; active = PIO_Get(pin) ? 0 : 1;
return active; return active;
} }

View File

@@ -1,57 +1,107 @@
/* Code to control the PERST lines of attached modems /* Code to control the PERST lines of attached modems
* *
* Depending on the board this is running on, it might be possible * 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 * for the controller to set the status of the PERST input line of
* the cellular modem. If the board supports this, it sets the * the cellular modem. If the board supports this, it sets the
* PIN_PERST1 and/or PIN_PERST2 defines in its board.h file. * PIN_PERST1 and/or PIN_PERST2 defines in its board.h file.
*/ */
#include "board.h" #include "board.h"
#include "trace.h"
#include "wwan_perst.h" #include "wwan_perst.h"
#include "osmocom/core/timer.h" #include <osmocom/core/timer.h>
#define PERST_DURATION_MS 300 struct wwan_perst {
uint8_t idx;
const Pin pin;
struct osmo_timer_list timer;
};
#ifdef PIN_PERST1 #ifdef PIN_PERST1
static const Pin pin_perst1 = PIN_PERST1; static struct wwan_perst perst1 = {
static struct osmo_timer_list perst1_timer; .idx = 0,
.pin = PIN_PERST1,
};
#endif #endif
#ifdef PIN_PERST2 #ifdef PIN_PERST2
static const Pin pin_perst2 = PIN_PERST2; static struct wwan_perst perst2 = {
static struct osmo_timer_list perst2_timer; .idx = 1,
.pin = PIN_PERST2,
};
#endif #endif
static int initialized = 0;
static void perst_tmr_cb(void *data) static void perst_tmr_cb(void *data)
{ {
const Pin *pin = data; struct wwan_perst *perst = data;
/* release the (low-active) reset */ /* release the (low-active) reset */
PIO_Clear(pin); TRACE_INFO("%u: De-asserting modem reset\r\n", perst->idx);
PIO_Clear(&perst->pin);
} }
int wwan_perst_do_reset(int modem_nr) static struct wwan_perst *get_perst_for_modem(int modem_nr)
{ {
const Pin *pin; if (!initialized) {
struct osmo_timer_list *tmr; TRACE_ERROR("Somebody forgot to call wwan_perst_init()\r\n");
wwan_perst_init();
}
switch (modem_nr) { switch (modem_nr) {
#ifdef PIN_PERST1 #ifdef PIN_PERST1
case 1: case 0:
pin = &pin_perst1; return &perst1;
tmr = &perst1_timer;
break;
#endif #endif
#ifdef PIN_PERST2 #ifdef PIN_PERST2
case 2: case 1:
pin = &pin_perst2; return &perst2;
tmr = &perst2_timer;
break;
#endif #endif
default: default:
return -1; 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);
} }
PIO_Set(pin);
osmo_timer_schedule(tmr, PERST_DURATION_MS/1000, (PERST_DURATION_MS%1000)*1000);
return 0; return 0;
} }
@@ -60,17 +110,18 @@ int wwan_perst_init(void)
{ {
int num_perst = 0; int num_perst = 0;
#ifdef PIN_PERST1 #ifdef PIN_PERST1
PIO_Configure(&pin_perst1, 1); PIO_Configure(&perst1.pin, 1);
perst1_timer.cb = perst_tmr_cb; perst1.timer.cb = perst_tmr_cb;
perst1_timer.data = (void *) &pin_perst1; perst1.timer.data = (void *) &perst1;
num_perst++; num_perst++;
#endif #endif
#ifdef PIN_PERST2 #ifdef PIN_PERST2
PIO_Configure(&pin_perst2, 1); PIO_Configure(&perst2.pin, 1);
perst2_timer.cb = perst_tmr_cb; perst2.timer.cb = perst_tmr_cb;
perst2_timer.data = (void *) &pin_perst2; perst2.timer.data = (void *) &perst2;
num_perst++; num_perst++;
#endif #endif
initialized = 1;
return num_perst; return num_perst;
} }

View File

@@ -1,85 +1,145 @@
/* SIMtrace with SAM3S board definition
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 #pragma once
#include "board_common.h" #include "board_common.h"
#include "simtrace_usb.h"
/** Name of the board */ /* Name of the board */
#define BOARD_NAME "SAM3S-SIMTRACE" #define BOARD_NAME "SAM3S-SIMTRACE"
/** Board definition */ /* Board definition */
#define simtrace #define simtrace
/* Board main oscillator frequency (in Hz) */
#define BOARD_MAINOSC 18432000 #define BOARD_MAINOSC 18432000
/** Phone (SIM card emulator)/CCID Reader/MITM configuration **/ /** Pin configuration **/
/* Normally the communication lines between phone and SIM card are disconnected */ /* Button to force bootloader start (shorted to ground when pressed */
// Disconnect SIM card I/O, VPP line from the phone lines #define PIN_BOOTLOADER_SW {PIO_PA31, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP}
// FIXME: Per default pins are input, therefore high-impedance, therefore they don not activate the bus switch, right? /* Enable powering the card using the second 3.3 V output of the LDO (active high) */
#define SIM_PWEN_PIN {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Enable powering the SIM card */
#define PWR_PINS SIM_PWEN_PIN
/* Card presence pin */
#define SW_SIM PIO_PA8
/* Pull card presence pin high (shorted to ground in card slot when card is present) */
#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_DEGLITCH | PIO_IT_EDGE }
/** Smart card connection **/
/* Card RST reset signal input (active low; RST_SIM in schematic) */
#define PIN_SIM_RST {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* 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}
/* 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
/** Phone connection **/
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH }
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Phone CLK clock input (CLK_PHONE in schematic) */
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used for phone USIM slot 1 communication */
#define PINS_USIM1 PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
#define PIN_PHONE_CLK_INPUT {PIO_PA29B_TCLK2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/** Default pin configuration **/
/* Disconnect VPP, CLK, and RST lines between card and phone using bus switch (high sets bus switch to high-impedance) */
#define PIN_SC_SW_DEFAULT {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_SC_SW_DEFAULT {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
// Disconnect SIM card RST, CLK line from the phone lines /* Disconnect I/O line between card and phone using bus switch (high sets bus switch to high-impedance) */
#define PIN_IO_SW_DEFAULT {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_IO_SW_DEFAULT {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Disconnect all lines (VPP, CLK, RST, and I/O) between card and phone */
#define PINS_BUS_DEFAULT PIN_SC_SW_DEFAULT, PIN_IO_SW_DEFAULT #define PINS_BUS_DEFAULT PIN_SC_SW_DEFAULT, PIN_IO_SW_DEFAULT
/** Sniffer configuration **/ /** Sniffer configuration **/
// Connect VPP, CLK and RST lines from smartcard to the phone /* Connect VPP, CLK, and RST lines between card and phone using bus switch (low connects signals on bus switch) */
#define PIN_SC_SW_SNIFF {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} #define PIN_SC_SW_SNIFF {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Connect I/O line between card and phone using bus switch (low connects signals on bus switch) */
#define PIN_IO_SW_SNIFF {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} #define PIN_IO_SW_SNIFF {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Connect all lines (VPP, CLK, RST, and I/O) between card and phone */
#define PINS_BUS_SNIFF PIN_SC_SW_SNIFF, PIN_IO_SW_SNIFF #define PINS_BUS_SNIFF PIN_SC_SW_SNIFF, PIN_IO_SW_SNIFF
/* 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
/* Disable power converter 4.5-6V to 3.3V (active high) */
#define PIN_SIM_PWEN_SNIFF {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Enable power switch to forward VCC_PHONE to VCC_SIM (active high) */
#define PIN_VCC_FWD_SNIFF {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Use phone VCC to power card */
#define PINS_PWR_SNIFF PIN_SIM_PWEN_SNIFF, PIN_VCC_FWD_SNIFF
#define PINS_SIM_SNIFF_SIM PIN_PHONE_IO, PIN_PHONE_CLK /** CCID configuration */
/* Card RST reset signal input (active low; RST_SIM in schematic) */
#define SIM_PWEN_PIN {PIO_PA5, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
#define PWR_PINS \
/* Enable power converter 4.5-6V to 3.3V; low: off */ \
{SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}, \
/* Enable second power converter: VCC_PHONE to VCC_SIM; high: on */ \
{VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
#define SW_SIM PIO_PA8
#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_DEGLITCH | PIO_IT_EDGE }
//#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOB, ID_PIOB, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_IT_EDGE}
/// PIN used for resetting the smartcard
// FIXME: Card is resetted with pin set to 0 --> PIO_OUTPUT_1 as default is right?
#define PIN_ISO7816_RSTMC {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} #define PIN_ISO7816_RSTMC {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* ISO7816-communication related pins */
/// Pins used for connect the smartcard
#define PIN_SIM_IO_INPUT {PIO_PA1, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PIN_SIM_IO {PIO_PA6, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define PIN_SIM_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_SIM_CLK_INPUT {PIO_PA4, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
//#define PINS_ISO7816 PIN_USART1_TXD, PIN_USART1_SCK, PIN_ISO7816_RSTMC
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2 #define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
#define PINS_TC PIN_SIM_IO_INPUT, PIN_SIM_CLK_INPUT /** External SPI flash interface **/
/* SPI MISO pin definition */
#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
/* SPI MOSI pin definition */
#define PIN_SPI_MOSI {PIO_PA13A_MOSI, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* SPI SCK pin definition */
#define PIN_SPI_SCK {PIO_PA14A_SPCK, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* SPI pins definition. Contains MISO, MOSI & SCK */
#define PINS_SPI PIN_SPI_MISO, PIN_SPI_MOSI, PIN_SPI_SCK
/* SPI chip select 0 pin definition */
#define PIN_SPI_NPCS0 {PIO_PA11A_NPCS0, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* SPI flash write protect pin (active low, pulled low) */
#define PIN_SPI_WP {PA15, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define VCC_PHONE {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} /** Pin configuration to control USB pull-up on D+
#define PIN_ISO7816_RST_PHONE {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH } * @details the USB pull-up on D+ is enable by default on the board but can be disabled by setting PA16 high
#define PIN_PHONE_IO_INPUT {PIO_PA21, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} */
#define PIN_PHONE_IO {PIO_PA22, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} #define PIN_USB_PULLUP {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} // External Clock Input on PA28
//#define PIN_PHONE_CLK {PIO_PA23A_SCK1, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} // External Clock Input on PA28
#define PIN_PHONE_CLK_INPUT {PIO_PA29, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PINS_ISO7816_PHONE PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, VCC_PHONE, PIN_PHONE_IO_INPUT, PIN_ISO7816_RST_PHONE
//, VCC_PHONE
/** USB definitions */
/* OpenMoko SIMtrace 2 USB vendor ID */
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
/* OpenMoko SIMtrace 2 USB product ID (main application/runtime mode) */
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2
/* OpenMoko SIMtrace 2 DFU USB product ID (DFU bootloader/DFU mode) */
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2_DFU
/* USB release number (bcdDevice, shown as 0.00) */
#define BOARD_USB_RELEASE 0x000
/* Indicate SIMtrace is bus power in USB attributes */
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP
//** SPI interface **/ /** Supported modes */
/// SPI MISO pin definition (PA12). /* SIMtrace board supports sniffer mode */
#define PIN_SPI_MISO {1 << 12, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
/// SPI MOSI pin definition (PA13).
#define PIN_SPI_MOSI {1 << 13, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/// SPI SPCK pin definition (PA14).
#define PIN_SPI_SPCK {1 << 14, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/// SPI pins definition. Contains MISO, MOSI & SPCK (PA12, PA13 & PA14).
#define PINS_SPI PIN_SPI_MISO, PIN_SPI_MOSI, PIN_SPI_SPCK
/// SPI chip select 0 pin definition (PA11).
#define PIN_SPI_NPCS0 {1 << 11, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define SIMTRACE_VENDOR_ID 0x1d50
#define SIMTRACE_PRODUCT_ID 0x60e3
#define USB_VENDOR_ID SIMTRACE_VENDOR_ID
#define USB_PRODUCT_ID SIMTRACE_PRODUCT_ID
#define HAVE_SNIFFER #define HAVE_SNIFFER
#define HAVE_CCID /* SIMtrace board supports CCID mode */
#define HAVE_CARDEM //#define HAVE_CCID
#define HAVE_MITM /* SIMtrace board supports card emulation mode */
//#define HAVE_CARDEM
/* SIMtrace board supports man-in-the-middle mode */
//#define HAVE_MITM

View File

@@ -0,0 +1,68 @@
/* SIMtrace with SAM3S specific application code
*
* (C) 2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 "sim_switch.h"
#include <osmocom/core/timer.h>
#include "usb_buf.h"
void board_exec_dbg_cmd(int ch)
{
switch (ch) {
case '?':
printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
NVIC_SystemReset();
break;
default:
printf("Unknown command '%c'\n\r", ch);
break;
}
}
void board_main_top(void)
{
#ifndef APPLICATION_dfu
usb_buf_init();
/* Initialize checking for card insert/remove events */
//card_present_init();
#endif
}
int board_override_enter_dfu(void)
{
const Pin bl_sw_pin = PIN_BOOTLOADER_SW;
PIO_Configure(&bl_sw_pin, 1);
/* Enter DFU bootloader in case the respective button is pressed */
if (PIO_Get(&bl_sw_pin) == 0) {
/* do not print to early since the console is not initialized yet */
//printf("BOOTLOADER switch pressed -> Force DFU\n\r");
return 1;
} else
return 0;
}

View File

@@ -89,7 +89,7 @@
/// \param condition Condition to verify. /// \param condition Condition to verify.
#define ASSERT(condition) { \ #define ASSERT(condition) { \
if (!(condition)) { \ if (!(condition)) { \
printf("-F- ASSERT: %s %s:%d\r\n", #condition, __BASE_FILE__, __LINE__); \ printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
while (1); \ while (1); \
} \ } \
} }

View File

@@ -1,3 +1,22 @@
/* ISO7816-3 state machine for the card side
*
* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 #pragma once
#include <stdint.h> #include <stdint.h>
@@ -10,7 +29,8 @@ enum card_io {
CARD_IO_CLK, CARD_IO_CLK,
}; };
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan); struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan,
uint8_t in_ep, uint8_t irq_ep);
/* process a single byte received from the reader */ /* process a single byte received from the reader */
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte); void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
@@ -25,7 +45,6 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active);
int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len); int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len);
struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch); struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch);
struct llist_head *card_emu_get_usb_tx_queue(struct card_handle *ch);
void card_emu_have_new_uart_tx(struct card_handle *ch); void card_emu_have_new_uart_tx(struct card_handle *ch);
void card_emu_report_status(struct card_handle *ch); void card_emu_report_status(struct card_handle *ch);
@@ -36,3 +55,4 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi);
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte); int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte);
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx); void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
void card_emu_uart_wait_tx_idle(uint8_t uart_chan); void card_emu_uart_wait_tx_idle(uint8_t uart_chan);
void card_emu_uart_interrupt(uint8_t uart_chan);

View File

@@ -1,135 +0,0 @@
#pragma once
/* Smart Card Emulation USB protocol */
/* (C) 2015 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 <stdint.h>
/* DT = Device Terminated. DO = Device Originated */
enum cardemu_usb_msg_type {
/* Bulk out pipe */
CEMU_USB_MSGT_DT_TX_DATA, /* TPDU Date */
CEMU_USB_MSGT_DT_SET_ATR, /* Set the ATR stored in simulator */
CEMU_USB_MSGT_DT_GET_STATS, /* request DO_STATS */
CEMU_USB_MSGT_DT_GET_STATUS, /* request DO_STATUS */
CEMU_USB_MSGT_DT_CARDINSERT, /* insert/remove card */
/* Bulk in pipe */
CEMU_USB_MSGT_DO_RX_DATA, /* TPDU data */
CEMU_USB_MSGT_DO_STATUS, /* Status information */
CEMU_USB_MSGT_DO_STATS, /* Statistics */
CEMU_USB_MSGT_DO_PTS, /* Information about PTS */
CEMU_USB_MSGT_DO_ERROR, /* Error message */
};
/* generic header, shared by all messages */
struct cardemu_usb_msg_hdr {
uint8_t msg_type; /* enum cardemu_usb_msg_type */
uint8_t seq_nr; /* sequence number */
uint16_t msg_len; /* length of message including hdr */
uint8_t data[0];
} __attribute__ ((packed));
/* indicates a TPDU header is present in this message */
#define CEMU_DATA_F_TPDU_HDR 0x00000001
/* indicates last part of transmission in this direction */
#define CEMU_DATA_F_FINAL 0x00000002
/* incdicates a PB is present and we should continue with TX */
#define CEMU_DATA_F_PB_AND_TX 0x00000004
/* incdicates a PB is present and we should continue with RX */
#define CEMU_DATA_F_PB_AND_RX 0x00000008
/* CEMU_USB_MSGT_DT_CARDINSERT */
struct cardemu_usb_msg_cardinsert {
struct cardemu_usb_msg_hdr hdr;
uint8_t card_insert;
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DT_SET_ATR */
struct cardemu_usb_msg_set_atr {
struct cardemu_usb_msg_hdr hdr;
uint8_t atr_len;
/* variable-length ATR data */
uint8_t atr[0];
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DT_TX_DATA */
struct cardemu_usb_msg_tx_data {
struct cardemu_usb_msg_hdr hdr;
uint32_t flags;
uint16_t data_len;
/* variable-length TPDU data */
uint8_t data[0];
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_RX_DATA */
struct cardemu_usb_msg_rx_data {
struct cardemu_usb_msg_hdr hdr;
uint32_t flags;
uint16_t data_len;
/* variable-length TPDU data */
uint8_t data[0];
} __attribute__ ((packed));
#define CEMU_STATUS_F_VCC_PRESENT 0x00000001
#define CEMU_STATUS_F_CLK_ACTIVE 0x00000002
#define CEMU_STATUS_F_RCEMU_ACTIVE 0x00000004
#define CEMU_STATUS_F_CARD_INSERT 0x00000008
#define CEMU_STATUS_F_RESET_ACTIVE 0x00000010
/* CEMU_USB_MSGT_DO_STATUS */
struct cardemu_usb_msg_status {
struct cardemu_usb_msg_hdr hdr;
uint32_t flags;
/* phone-applied target voltage in mV */
uint16_t voltage_mv;
/* Fi/Di related information */
uint8_t fi;
uint8_t di;
uint8_t wi;
uint32_t waiting_time;
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_PTS */
struct cardemu_usb_msg_pts_info {
struct cardemu_usb_msg_hdr hdr;
uint8_t pts_len;
/* PTS request as sent from reader */
uint8_t req[6];
/* PTS response as sent by card */
uint8_t resp[6];
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_ERROR */
struct cardemu_usb_msg_error {
struct cardemu_usb_msg_hdr hdr;
uint8_t severity;
uint8_t subsystem;
uint16_t code;
uint8_t msg_len;
/* human-readable error message */
uint8_t msg[0];
} __attribute__ ((packed));
static inline void cardemu_hdr_set(struct cardemu_usb_msg_hdr *hdr, uint16_t msgt)
{
memset(hdr, 0, sizeof(*hdr));
hdr->msg_type = msgt;
}

View File

@@ -1,6 +1,30 @@
/* ISO7816-3 Fi/Di tables + computation
*
* (C) 2010-2015 by Harald Welte <laforge@gnumonks.org>
*
* 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 #pragma once
#include <stdint.h> #include <stdint.h>
/* Table 7 of ISO 7816-3:2006 */
extern const uint16_t fi_table[];
/* Table 8 from ISO 7816-3:2006 */
extern const uint8_t di_table[];
/* compute the F/D ratio based on Fi and Di values */ /* compute the F/D ratio based on Fi and Di values */
int compute_fidi_ratio(uint8_t fi, uint8_t di); int compute_fidi_ratio(uint8_t fi, uint8_t di);

View File

@@ -1,11 +1,42 @@
/* IRQ-safe linked lists
*
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
*
* 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 #pragma once
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include "utils.h"
static inline void llist_add_irqsafe(struct llist_head *_new,
struct llist_head *head)
{
unsigned long x;
local_irq_save(x);
llist_add(_new, head);
local_irq_restore(x);
}
static inline void llist_add_tail_irqsafe(struct llist_head *_new, static inline void llist_add_tail_irqsafe(struct llist_head *_new,
struct llist_head *head) struct llist_head *head)
{ {
__disable_irq(); unsigned long x;
local_irq_save(x);
llist_add_tail(_new, head); llist_add_tail(_new, head);
__enable_irq(); __enable_irq();
} }
@@ -13,15 +44,16 @@ static inline void llist_add_tail_irqsafe(struct llist_head *_new,
static inline struct llist_head *llist_head_dequeue_irqsafe(struct llist_head *head) static inline struct llist_head *llist_head_dequeue_irqsafe(struct llist_head *head)
{ {
struct llist_head *lh; struct llist_head *lh;
unsigned long x;
__disable_irq(); local_irq_save(x);
if (llist_empty(head)) { if (llist_empty(head)) {
lh = NULL; lh = NULL;
} else { } else {
lh = head->next; lh = head->next;
llist_del(lh); llist_del(lh);
} }
__enable_irq(); local_irq_restore(x);
return lh; return lh;
} }

View File

@@ -1,61 +0,0 @@
#pragma once
#define RCTX_SIZE_LARGE 960
#define RCTX_SIZE_SMALL 320
#define MAX_HDRSIZE sizeof(struct openpcd_hdr)
#include <stdint.h>
#include "osmocom/core/linuxlist.h"
#define __ramfunc
enum req_ctx_state {
/* free to be allocated */
RCTX_S_FREE,
/* USB -> UART */
/* In USB driver, waiting for data from host */
RCTX_S_USB_RX_BUSY,
/* somewhere in the main loop */
RCTX_S_MAIN_PROCESSING,
/* pending (in queue) for transmission on UART */
RCTX_S_UART_TX_PENDING,
/* currently in active transmission on UART */
RCTX_S_UART_TX_BUSY,
/* UART -> USB */
/* currently in active reception on UART */
RCTX_S_UART_RX_BUSY,
/* pending (in queue) for transmission over USB to host */
RCTX_S_USB_TX_PENDING,
/* currently in transmission over USB to host */
RCTX_S_USB_TX_BUSY,
/* number of states */
RCTX_STATE_COUNT
};
struct req_ctx {
/* if this req_ctx is on a queue... */
struct llist_head list;
uint32_t ep;
/* enum req_ctx_state */
volatile uint32_t state;
/* size of th 'data' buffer */
uint16_t size;
/* total number of used bytes in buffer */
uint16_t tot_len;
/* index into the buffer, user specific */
uint16_t idx;
/* actual data buffer */
uint8_t *data;
};
extern void req_ctx_init(void);
extern struct req_ctx __ramfunc *req_ctx_find_get(int large, uint32_t old_state, uint32_t new_state);
extern struct req_ctx *req_ctx_find_busy(void);
extern void req_ctx_set_state(struct req_ctx *ctx, uint32_t new_state);
extern void req_ctx_put(struct req_ctx *ctx);
extern uint8_t req_ctx_num(struct req_ctx *ctx);
unsigned int req_ctx_count(uint32_t state);

View File

@@ -1,3 +1,19 @@
/* Ring buffer
*
* 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
*/
#ifndef SIMTRACE_RINGBUF_H #ifndef SIMTRACE_RINGBUF_H
#define SIMTRACE_RINGBUF_H #define SIMTRACE_RINGBUF_H
@@ -5,7 +21,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h> #include <sys/types.h>
#define RING_BUFLEN 128 #define RING_BUFLEN 512
typedef struct ringbuf { typedef struct ringbuf {
uint8_t buf[RING_BUFLEN]; uint8_t buf[RING_BUFLEN];
@@ -16,7 +32,7 @@ typedef struct ringbuf {
void rbuf_reset(volatile ringbuf * rb); void rbuf_reset(volatile ringbuf * rb);
uint8_t rbuf_read(volatile ringbuf * rb); uint8_t rbuf_read(volatile ringbuf * rb);
uint8_t rbuf_peek(volatile ringbuf * rb); uint8_t rbuf_peek(volatile ringbuf * rb);
void rbuf_write(volatile ringbuf * rb, uint8_t item); int rbuf_write(volatile ringbuf * rb, uint8_t item);
bool rbuf_is_empty(volatile ringbuf * rb); bool rbuf_is_empty(volatile ringbuf * rb);
bool rbuf_is_full(volatile ringbuf * rb); bool rbuf_is_full(volatile ringbuf * rb);

View File

@@ -1,24 +1,30 @@
/* SIMtrace 2 mode definitions
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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
*/
#ifndef SIMTRACE_H #ifndef SIMTRACE_H
#define SIMTRACE_H #define SIMTRACE_H
#include "ringbuffer.h" #include "ringbuffer.h"
#include "board.h" #include "board.h"
#include <usb/device/dfu/dfu.h>
/* Endpoint numbers */
#define DATAOUT 1
#define DATAIN 2
#define INT 3
#define BUFLEN 512 #define BUFLEN 512
#define PHONE_DATAOUT 4
#define PHONE_DATAIN 5
#define PHONE_INT 6
#define CARDEM_USIM2_DATAOUT DATAOUT
#define CARDEM_USIM2_DATAIN DATAIN
#define CARDEM_USIM2_INT INT
#define CLK_MASTER true #define CLK_MASTER true
#define CLK_SLAVE false #define CLK_SLAVE false
@@ -71,12 +77,16 @@ typedef struct {
USBEndpointDescriptor bulkIn; USBEndpointDescriptor bulkIn;
/// Interrupt OUT endpoint descriptor /// Interrupt OUT endpoint descriptor
USBEndpointDescriptor interruptIn; USBEndpointDescriptor interruptIn;
DFURT_IF_DESCRIPTOR_STRUCT
} __attribute__ ((packed)) CCIDDriverConfigurationDescriptors; } __attribute__ ((packed)) CCIDDriverConfigurationDescriptors;
extern const USBConfigurationDescriptor *configurationDescriptorsArr[]; extern const USBConfigurationDescriptor *configurationDescriptorsArr[];
int check_data_from_phone(); /*! Update USART baud rate to Fi/Di ratio
void update_fidi(uint8_t fidi); * @param[io] usart USART peripheral base address
* @param[in] fidi FiDi value as provided in TA interface byte
*/
void update_fidi(Usart_info *usart, uint8_t fidi);
void ISR_PhoneRST( const Pin *pPin); void ISR_PhoneRST( const Pin *pPin);
@@ -106,6 +116,9 @@ extern void CCID_run( void );
extern void mode_cardemu_run(void); extern void mode_cardemu_run(void);
extern void MITM_run( void ); extern void MITM_run( void );
/* IRQ functions */
extern void Sniffer_usart0_irq(void);
extern void Sniffer_usart1_irq(void);
extern void mode_cardemu_usart0_irq(void); extern void mode_cardemu_usart0_irq(void);
extern void mode_cardemu_usart1_irq(void); extern void mode_cardemu_usart1_irq(void);
@@ -113,8 +126,4 @@ extern void mode_cardemu_usart1_irq(void);
void Timer_Init( void ); void Timer_Init( void );
void TC0_Counter_Reset( void ); void TC0_Counter_Reset( void );
struct llist_head;
int usb_refill_to_host(struct llist_head *queue, uint32_t ep);
int usb_refill_from_host(struct llist_head *queue, int ep);
#endif /* SIMTRACE_H */ #endif /* SIMTRACE_H */

View File

@@ -0,0 +1,322 @@
/* SIMtrace2 USB protocol
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 <stdint.h>
#include <stdbool.h>
/***********************************************************************
* COMMON HEADER
***********************************************************************/
enum simtrace_msg_class {
SIMTRACE_MSGC_GENERIC = 0,
/* Card Emulation / Forwarding */
SIMTRACE_MSGC_CARDEM,
/* Modem Control (if modem is attached next to device) */
SIMTRACE_MSGC_MODEM,
/* Reader/phone-car/SIM communication sniff */
SIMTRACE_MSGC_SNIFF,
/* first vendor-specific request */
_SIMTRACE_MGSC_VENDOR_FIRST = 127,
};
enum simtrace_msg_type_generic {
/* Generic Error Message */
SIMTRACE_CMD_DO_ERROR = 0,
/* Request/Response for simtrace_board_info */
SIMTRACE_CMD_BD_BOARD_INFO,
};
/* SIMTRACE_MSGC_CARDEM */
enum simtrace_msg_type_cardem {
/* TPDU Data to be transmitted to phone */
SIMTRACE_MSGT_DT_CEMU_TX_DATA = 1,
/* Set the ATR to be returned at phone-SIM reset */
SIMTRACE_MSGT_DT_CEMU_SET_ATR,
/* Get Statistics Request / Response */
SIMTRACE_MSGT_BD_CEMU_STATS,
/* Get Status Request / Response */
SIMTRACE_MSGT_BD_CEMU_STATUS,
/* Request / Confirm emulated card insert */
SIMTRACE_MSGT_DT_CEMU_CARDINSERT,
/* TPDU Data received from phomne */
SIMTRACE_MSGT_DO_CEMU_RX_DATA,
/* Indicate PTS request from phone */
SIMTRACE_MSGT_DO_CEMU_PTS,
};
/* SIMTRACE_MSGC_MODEM */
enum simtrace_msg_type_modem {
/* Modem Control: Reset an attached modem */
SIMTRACE_MSGT_DT_MODEM_RESET = 1,
/* Modem Control: Select local / remote SIM */
SIMTRACE_MSGT_DT_MODEM_SIM_SELECT,
/* Modem Control: Status (WWAN LED, SIM Presence) */
SIMTRACE_MSGT_BD_MODEM_STATUS,
};
/* SIMTRACE_MSGC_SNIFF */
enum simtrace_msg_type_sniff {
/* Status change (card inserted, reset, ...) */
SIMTRACE_MSGT_SNIFF_CHANGE = 0,
/* Fi/Di baudrate change */
SIMTRACE_MSGT_SNIFF_FIDI,
/* ATR data */
SIMTRACE_MSGT_SNIFF_ATR,
/* PPS (request or response) data */
SIMTRACE_MSGT_SNIFF_PPS,
/* TPDU data */
SIMTRACE_MSGT_SNIFF_TPDU,
};
/* common message header */
struct simtrace_msg_hdr {
uint8_t msg_class; /* simtrace_msg_class */
uint8_t msg_type; /* simtrace_msg_type_xxx */
uint8_t seq_nr;
uint8_t slot_nr; /* SIM slot number */
uint16_t _reserved;
uint16_t msg_len; /* length including header */
uint8_t payload[0];
} __attribute__ ((packed));
/***********************************************************************
* Capabilities
***********************************************************************/
/* generic capabilities */
enum simtrace_capability_generic {
/* compatible with 5V SIM card interface */
SIMTRACE_CAP_VOLT_5V,
/* compatible with 3.3V SIM card interface */
SIMTRACE_CAP_VOLT_3V3,
/* compatible with 1.8V SIM card interface */
SIMTRACE_CAP_VOLT_1V8,
/* Has LED1 */
SIMTRACE_CAP_LED_1,
/* Has LED2 */
SIMTRACE_CAP_LED_2,
/* Has Single-Pole Dual-Throw (local/remote SIM) */
SIMTRACE_CAP_SPDT,
/* Has Bus-Switch (trace / MITM) */
SIMTRACE_CAP_BUS_SWITCH,
/* Can read VSIM via ADC */
SIMTRACE_CAP_VSIM_ADC,
/* Can read temperature via ADC */
SIMTRACE_CAP_TEMP_ADC,
/* Supports DFU for firmware update */
SIMTRACE_CAP_DFU,
/* Supports Ctrl EP command for erasing flash / return to SAM-BA */
SIMTRACE_CAP_ERASE_FLASH,
/* Can read the status of card insert contact */
SIMTRACE_CAP_READ_CARD_DET,
/* Can control the status of a simulated card insert */
SIMTRACE_CAP_ASSERT_CARD_DET,
/* Can toggle the hardware reset of an attached modem */
SIMTRACE_CAP_ASSERT_MODEM_RST,
};
/* vendor-specific capabilities of sysmocom devices */
enum simtrace_capability_vendor {
/* Can erase a peer SAM3 controller */
SIMTRACE_CAP_SYSMO_QMOD_ERASE_PEER,
/* Can read/write an attached EEPROM */
SIMTRACE_CAP_SYSMO_QMOD_RW_EEPROM,
/* can reset an attached USB hub */
SIMTRACE_CAP_SYSMO_QMOD_RESET_HUB,
};
/* SIMTRACE_CMD_BD_BOARD_INFO */
struct simtrace_board_info {
struct {
char manufacturer[32];
char model[32];
char version[32];
} hardware;
struct {
/* who provided this software? */
char provider[32];
/* name of software image */
char name[32];
/* (git) version at build time */
char version[32];
/* built on which machine? */
char buildhost[32];
/* CRC-32 over software image */
uint32_t crc;
} software;
struct {
/* Maximum baud rate supported */
uint32_t max_baud_rate;
} speed;
/* number of bytes of generic capability bit-mask */
uint8_t cap_generic_bytes;
/* number of bytes of vendor capability bit-mask */
uint8_t cap_vendor_bytes;
uint8_t data[0];
/* cap_generic + cap_vendor */
} __attribute__ ((packed));
/***********************************************************************
* CARD EMULATOR / FORWARDER
***********************************************************************/
/* indicates a TPDU header is present in this message */
#define CEMU_DATA_F_TPDU_HDR 0x00000001
/* indicates last part of transmission in this direction */
#define CEMU_DATA_F_FINAL 0x00000002
/* incdicates a PB is present and we should continue with TX */
#define CEMU_DATA_F_PB_AND_TX 0x00000004
/* incdicates a PB is present and we should continue with RX */
#define CEMU_DATA_F_PB_AND_RX 0x00000008
/* CEMU_USB_MSGT_DT_CARDINSERT */
struct cardemu_usb_msg_cardinsert {
uint8_t card_insert;
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DT_SET_ATR */
struct cardemu_usb_msg_set_atr {
uint8_t atr_len;
/* variable-length ATR data */
uint8_t atr[0];
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DT_TX_DATA */
struct cardemu_usb_msg_tx_data {
uint32_t flags;
uint16_t data_len;
/* variable-length TPDU data */
uint8_t data[0];
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_RX_DATA */
struct cardemu_usb_msg_rx_data {
uint32_t flags;
uint16_t data_len;
/* variable-length TPDU data */
uint8_t data[0];
} __attribute__ ((packed));
#define CEMU_STATUS_F_VCC_PRESENT 0x00000001
#define CEMU_STATUS_F_CLK_ACTIVE 0x00000002
#define CEMU_STATUS_F_RCEMU_ACTIVE 0x00000004
#define CEMU_STATUS_F_CARD_INSERT 0x00000008
#define CEMU_STATUS_F_RESET_ACTIVE 0x00000010
/* CEMU_USB_MSGT_DO_STATUS */
struct cardemu_usb_msg_status {
uint32_t flags;
/* phone-applied target voltage in mV */
uint16_t voltage_mv;
/* Fi/Di related information */
uint8_t fi;
uint8_t di;
uint8_t wi;
uint32_t waiting_time;
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_PTS */
struct cardemu_usb_msg_pts_info {
uint8_t pts_len;
/* PTS request as sent from reader */
uint8_t req[6];
/* PTS response as sent by card */
uint8_t resp[6];
} __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_ERROR */
struct cardemu_usb_msg_error {
uint8_t severity;
uint8_t subsystem;
uint16_t code;
uint8_t msg_len;
/* human-readable error message */
uint8_t msg[0];
} __attribute__ ((packed));
/***********************************************************************
* MODEM CONTROL
***********************************************************************/
/* SIMTRACE_MSGT_DT_MODEM_RESET */
struct st_modem_reset {
/* 0: de-assert reset, 1: assert reset, 2: pulse reset */
uint8_t asserted;
/* if above is '2', duration of pulse in ms */
uint16_t pulse_duration_msec;
} __attribute__((packed));
/* SIMTRACE_MSGT_DT_MODEM_SIM_SELECT */
struct st_modem_sim_select {
/* remote (1), local (0) */
uint8_t remote_sim;
} __attribute__((packed));
/* SIMTRACE_MSGT_BD_MODEM_STATUS */
#define ST_MDM_STS_BIT_WWAN_LED (1 << 0)
#define ST_MDM_STS_BIT_CARD_INSERTED (1 << 1)
struct st_modem_status {
/* bit-field of supported status bits */
uint8_t supported_mask;
/* bit-field of current status bits */
uint8_t status_mask;
/* bit-field of changed status bits */
uint8_t changed_mask;
} __attribute__((packed));
/***********************************************************************
* SNIFF
***********************************************************************/
/* SIMTRACE_MSGT_SNIFF_CHANGE flags */
#define SNIFF_CHANGE_FLAG_CARD_INSERT (1<<0)
#define SNIFF_CHANGE_FLAG_CARD_EJECT (1<<1)
#define SNIFF_CHANGE_FLAG_RESET_ASSERT (1<<2)
#define SNIFF_CHANGE_FLAG_RESET_DEASSERT (1<<3)
#define SNIFF_CHANGE_FLAG_TIMEOUT_WT (1<<4)
/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU flags */
#define SNIFF_DATA_FLAG_ERROR_INCOMPLETE (1<<5)
#define SNIFF_DATA_FLAG_ERROR_MALFORMED (1<<6)
#define SNIFF_DATA_FLAG_ERROR_CHECKSUM (1<<7)
/* SIMTRACE_MSGT_SNIFF_CHANGE */
struct sniff_change {
/* SIMTRACE_MSGT_SNIFF_CHANGE flags */
uint32_t flags;
} __attribute__ ((packed));
/* SIMTRACE_MSGT_SNIFF_FIDI */
struct sniff_fidi {
/* Fi/Di values as encoded in TA1 */
uint8_t fidi;
} __attribute__ ((packed));
/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU */
struct sniff_data {
/* data flags */
uint32_t flags;
/* data length */
uint16_t length;
/* data */
uint8_t data[0];
} __attribute__ ((packed));

View File

@@ -0,0 +1,67 @@
/* SIMtrace 2 USB definitions
*
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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
*/
/* SIMtrace USB IDs */
#define USB_VENDOR_OPENMOKO 0x1d50
#define USB_PRODUCT_OWHW_SAM3_DFU 0x4001 /* was 0x4000 */
#define USB_PRODUCT_OWHW_SAM3 0x4001
#define USB_PRODUCT_QMOD_HUB 0x4002
#define USB_PRODUCT_QMOD_SAM3_DFU 0x4004 /* was 0x4003 */
#define USB_PRODUCT_QMOD_SAM3 0x4004
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
#define USB_PRODUCT_SIMTRACE2 0x60e3
/* USB proprietary class */
#define USB_CLASS_PROPRIETARY 0xff
/* SIMtrace USB sub-classes */
/*! Sniffer USB sub-class */
#define SIMTRACE_SNIFFER_USB_SUBCLASS 1
/*! Card-emulation USB sub-class */
#define SIMTRACE_CARDEM_USB_SUBCLASS 2
/* Generic USB endpoint numbers */
/*! Card-side USB data out (host to device) endpoint number */
#define SIMTRACE_USB_EP_CARD_DATAOUT 1
/*! Card-side USB data in (device to host) endpoint number */
#define SIMTRACE_USB_EP_CARD_DATAIN 2
/*! Card-side USB interrupt endpoint number */
#define SIMTRACE_USB_EP_CARD_INT 3
/*! Phone-side USB data out (host to device) endpoint number */
#define SIMTRACE_USB_EP_PHONE_DATAOUT 4
/*! Phone-side USB data in (device to host) endpoint number */
#define SIMTRACE_USB_EP_PHONE_DATAIN 5
/*! Phone-side USB interrupt endpoint number */
#define SIMTRACE_USB_EP_PHONE_INT 6
/* Card-emulation USB endpoint numbers */
/*! USIM1 USB data out (host to device) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT 4
/*! USIM1 USB data in (device to host) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN 5
/*! USIM1 USB interrupt endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM1_INT 6
/*! USIM2 USB data out (host to device) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT 1
/*! USIM2 USB data in (device to host) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN 2
/*! USIM2 USB interrupt endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM2_INT 3
/*! Maximum number of endpoints */
#define BOARD_USB_NUMENDPOINTS 6

View File

@@ -1,3 +1,31 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
@@ -24,9 +52,14 @@ signed int printf(const char *pFormat, ...);
signed int sprintf(char *pStr, const char *pFormat, ...); signed int sprintf(char *pStr, const char *pFormat, ...);
signed int puts(const char *pStr); signed int puts(const char *pStr);
int fputc(int c, FILE *stream); int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream); int fputs(const char *s, FILE *stream);
#define putc(c, stream) fputc(c, stream) #define putc(c, stream) fputc(c, stream)
#define putchar(c) fputc(c, stdout) #define putchar(c) fputc(c, stdout)
signed int vfprintf_sync(FILE *pStream, const char *pFormat, va_list ap);
signed int vprintf_sync(const char *pFormat, va_list ap);
signed int printf_sync(const char *pFormat, ...);
int fputc_sync(int c, FILE *stream);
int fputs_sync(const char *s, FILE *stream);

View File

@@ -0,0 +1,41 @@
/* Memory allocation library
*
* 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 <stdlib.h>
#include <stdarg.h>
/* minimalistic emulation of core talloc API functions used by msgb.c */
#define __TALLOC_STRING_LINE1__(s) #s
#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
void *_talloc_zero(const void *ctx, size_t size, const char *name);
#define talloc_free(ctx) _talloc_free(ctx, __location__)
int _talloc_free(void *ptr, const char *location);
/* Unsupported! */
#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
void *talloc_named_const(const void *context, size_t size, const char *name);
void talloc_set_name_const(const void *ptr, const char *name);
char *talloc_strdup(const void *t, const char *p);
void *talloc_pool(const void *context, size_t size);

View File

@@ -0,0 +1,44 @@
/* USB buffer library
*
* 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 <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
/* buffered USB endpoint (with queue of msgb) */
struct usb_buffered_ep {
/* endpoint number */
uint8_t ep;
/* OUT endpoint (1) or IN/IRQ (0)? */
uint8_t out_from_host;
/* currently any transfer in progress? */
volatile uint32_t in_progress;
/* Tx queue (IN) / Rx queue (OUT) */
struct llist_head queue;
};
struct msgb *usb_buf_alloc(uint8_t ep);
void usb_buf_free(struct msgb *msg);
int usb_buf_submit(struct msgb *msg);
struct llist_head *usb_get_queue(uint8_t ep);
int usb_drain_queue(uint8_t ep);
void usb_buf_init(void);
struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep);
int usb_refill_to_host(uint8_t ep);
int usb_refill_from_host(uint8_t ep);

View File

@@ -1,3 +1,19 @@
/* General utilities
*
* 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 #pragma once
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

View File

@@ -1,5 +1,7 @@
/* ISO7816-3 state machine for the card side */ /* ISO7816-3 state machine for the card side
/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de> *
* (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -13,12 +15,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
*/ */
//#define TRACE_LEVEL 6
#include <stdio.h> #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@@ -31,9 +29,10 @@
#include "iso7816_fidi.h" #include "iso7816_fidi.h"
#include "tc_etu.h" #include "tc_etu.h"
#include "card_emu.h" #include "card_emu.h"
#include "req_ctx.h" #include "simtrace_prot.h"
#include "cardemu_prot.h" #include "usb_buf.h"
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#define NUM_SLOTS 2 #define NUM_SLOTS 2
@@ -55,6 +54,22 @@ enum iso7816_3_card_state {
ISO_S_IN_TPDU, /* inside a TPDU */ ISO_S_IN_TPDU, /* inside a TPDU */
}; };
const struct value_string iso7816_3_card_state_names[] = {
OSMO_VALUE_STRING(ISO_S_WAIT_POWER),
OSMO_VALUE_STRING(ISO_S_WAIT_CLK),
OSMO_VALUE_STRING(ISO_S_WAIT_RST),
OSMO_VALUE_STRING(ISO_S_WAIT_ATR),
OSMO_VALUE_STRING(ISO_S_IN_ATR),
OSMO_VALUE_STRING(ISO_S_IN_PTS),
OSMO_VALUE_STRING(ISO_S_WAIT_TPDU),
OSMO_VALUE_STRING(ISO_S_IN_TPDU),
{
.value = 0,
.str = NULL,
},
};
/* detailed sub-states of ISO_S_IN_PTS */ /* detailed sub-states of ISO_S_IN_PTS */
enum pts_state { enum pts_state {
PTS_S_WAIT_REQ_PTSS, PTS_S_WAIT_REQ_PTSS,
@@ -86,7 +101,7 @@ enum tpdu_state {
TPDU_S_WAIT_P2, /* waiting for P2 byte from reader */ TPDU_S_WAIT_P2, /* waiting for P2 byte from reader */
TPDU_S_WAIT_P3, /* waiting for P3 byte from reader */ TPDU_S_WAIT_P3, /* waiting for P3 byte from reader */
TPDU_S_WAIT_PB, /* waiting for Tx of procedure byte */ TPDU_S_WAIT_PB, /* waiting for Tx of procedure byte */
TPDU_S_WAIT_RX, /* waiitng for more data from reader */ TPDU_S_WAIT_RX, /* waiting for more data from reader */
TPDU_S_WAIT_TX, /* waiting for more data to reader */ TPDU_S_WAIT_TX, /* waiting for more data to reader */
}; };
@@ -97,7 +112,7 @@ enum tpdu_state {
#define _P3 4 #define _P3 4
struct card_handle { struct card_handle {
uint32_t num; unsigned int num;
enum iso7816_3_card_state state; enum iso7816_3_card_state state;
@@ -114,6 +129,9 @@ struct card_handle {
uint8_t tc_chan; /* TC channel number */ uint8_t tc_chan; /* TC channel number */
uint8_t uart_chan; /* UART channel */ uint8_t uart_chan; /* UART channel */
uint8_t in_ep; /* USB IN EP */
uint8_t irq_ep; /* USB IN EP */
uint32_t waiting_time; /* in clocks */ uint32_t waiting_time; /* in clocks */
/* ATR state machine */ /* ATR state machine */
@@ -138,10 +156,9 @@ struct card_handle {
uint8_t hdr[5]; /* CLA INS P1 P2 P3 */ uint8_t hdr[5]; /* CLA INS P1 P2 P3 */
} tpdu; } tpdu;
struct req_ctx *uart_rx_ctx; /* UART RX -> USB TX */ struct msgb *uart_rx_msg; /* UART RX -> USB TX */
struct req_ctx *uart_tx_ctx; /* USB RX -> UART TX */ struct msgb *uart_tx_msg; /* USB RX -> UART TX */
struct llist_head usb_tx_queue;
struct llist_head uart_tx_queue; struct llist_head uart_tx_queue;
struct { struct {
@@ -151,11 +168,6 @@ struct card_handle {
} stats; } stats;
}; };
struct llist_head *card_emu_get_usb_tx_queue(struct card_handle *ch)
{
return &ch->usb_tx_queue;
}
struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch) struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
{ {
return &ch->uart_tx_queue; return &ch->uart_tx_queue;
@@ -164,29 +176,60 @@ struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts); static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts);
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss); static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss);
static void flush_rx_buffer(struct card_handle *ch) /* update simtrace header msg_len and submit USB buffer */
void usb_buf_upd_len_and_submit(struct msgb *msg)
{ {
struct req_ctx *rctx; struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
struct cardemu_usb_msg_rx_data *rd;
rctx = ch->uart_rx_ctx; sh->msg_len = msgb_length(msg);
if (!rctx)
return;
ch->uart_rx_ctx = NULL; usb_buf_submit(msg);
/* store length of data payload fild in header */
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
rd->data_len = rctx->idx;
rd->hdr.msg_len = sizeof(*rd) + rd->data_len;
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
/* no need for irqsafe operation, as the usb_tx_queue is
* processed only by the main loop context */
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
} }
/* convert a non-contiguous PTS request/responsei into a contiguous /* Allocate USB buffer and push + initialize simtrace_msg_hdr */
struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
{
struct msgb *msg;
struct simtrace_msg_hdr *sh;
msg = usb_buf_alloc(ep);
if (!msg)
return NULL;
msg->l1h = msgb_put(msg, sizeof(*sh));
sh = (struct simtrace_msg_hdr *) msg->l1h;
memset(sh, 0, sizeof(*sh));
sh->msg_class = msg_class;
sh->msg_type = msg_type;
msg->l2h = msg->l1h + sizeof(*sh);
return msg;
}
/* Update cardemu_usb_msg_rx_data length + submit buffer */
static void flush_rx_buffer(struct card_handle *ch)
{
struct msgb *msg;
struct cardemu_usb_msg_rx_data *rd;
uint32_t data_len;
msg = ch->uart_rx_msg;
if (!msg)
return;
ch->uart_rx_msg = NULL;
/* store length of data payload field in header */
rd = (struct cardemu_usb_msg_rx_data *) msg->l2h;
rd->data_len = msgb_l2len(msg) - sizeof(*rd);
TRACE_INFO("%u: %s (%u)\n\r",
ch->num, __func__, rd->data_len);
usb_buf_upd_len_and_submit(msg);
}
/* convert a non-contiguous PTS request/response into a contiguous
* buffer, returning the number of bytes used in the buffer */ * buffer, returning the number of bytes used in the buffer */
static int serialize_pts(uint8_t *out, const uint8_t *in) static int serialize_pts(uint8_t *out, const uint8_t *in)
{ {
@@ -223,23 +266,18 @@ static uint8_t csum_pts(const uint8_t *in)
static void flush_pts(struct card_handle *ch) static void flush_pts(struct card_handle *ch)
{ {
struct req_ctx *rctx; struct msgb *msg;
struct cardemu_usb_msg_pts_info *ptsi; struct cardemu_usb_msg_pts_info *ptsi;
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY); msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DO_CEMU_PTS);
if (!rctx) if (!msg)
return; return;
ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data; ptsi = (struct cardemu_usb_msg_pts_info *) msgb_put(msg, sizeof(*ptsi));
ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS;
ptsi->hdr.msg_len = sizeof(*ptsi);
ptsi->pts_len = serialize_pts(ptsi->req, ch->pts.req); ptsi->pts_len = serialize_pts(ptsi->req, ch->pts.req);
serialize_pts(ptsi->resp, ch->pts.resp); serialize_pts(ptsi->resp, ch->pts.resp);
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING); usb_buf_upd_len_and_submit(msg);
/* no need for irqsafe operation, as the usb_tx_queue is
* processed only by the main loop context */
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
} }
static void emu_update_fidi(struct card_handle *ch) static void emu_update_fidi(struct card_handle *ch)
@@ -266,8 +304,9 @@ static void card_set_state(struct card_handle *ch,
if (ch->state == new_state) if (ch->state == new_state)
return; return;
TRACE_DEBUG("%u: 7816 card state %u -> %u\r\n", ch->num, TRACE_DEBUG("%u: 7816 card state %u (%s) -> %u (%s)\r\n", ch->num,
ch->state, new_state); ch->state, get_value_string(iso7816_3_card_state_names, ch->state),
new_state, get_value_string(iso7816_3_card_state_names, new_state));
ch->state = new_state; ch->state = new_state;
switch (new_state) { switch (new_state) {
@@ -278,32 +317,39 @@ static void card_set_state(struct card_handle *ch,
card_emu_uart_enable(ch->uart_chan, 0); card_emu_uart_enable(ch->uart_chan, 0);
break; break;
case ISO_S_WAIT_ATR: case ISO_S_WAIT_ATR:
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* Reset to initial Fi / Di ratio */ /* Reset to initial Fi / Di ratio */
ch->fi = 1; ch->fi = 1;
ch->di = 1; ch->di = 1;
emu_update_fidi(ch); emu_update_fidi(ch);
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
* we use the tc_etu mechanism to wait this time.
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
*/
tc_etu_set_wtime(ch->tc_chan, 2);
/* ensure the TC_ETU timer is enabled */
tc_etu_enable(ch->tc_chan);
break;
case ISO_S_IN_ATR:
/* initialize to default WI, this will be overwritten if we /* initialize to default WI, this will be overwritten if we
* receive TC2, and it will be programmed into hardware after * send TC2, and it will be programmed into hardware after
* ATR is finished */ * ATR is finished */
ch->wi = ISO7816_3_DEFAULT_WI; ch->wi = ISO7816_3_DEFAULT_WI;
/* update waiting time to initial waiting time */ /* update waiting time to initial waiting time */
ch->waiting_time = ISO7816_3_INIT_WTIME; ch->waiting_time = ISO7816_3_INIT_WTIME;
/* set initial waiting time */
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time); tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* Set ATR sub-state to initial state */ /* Set ATR sub-state to initial state */
ch->atr.idx = 0; ch->atr.idx = 0;
//set_atr_state(ch, ATR_S_WAIT_TS); /* enable USART transmission to reader */
/* Notice that we are just coming out of reset */
//ch->sh.flags |= SIMTRACE_FLAG_ATR;
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
break; /* trigger USART TX IRQ to sent first ATR byte TS */
card_emu_uart_interrupt(ch->uart_chan);
break; break;
case ISO_S_WAIT_TPDU: case ISO_S_WAIT_TPDU:
/* enable the receiver, disable transmitter */ /* enable the receiver, disable transmitter */
set_tpdu_state(ch, TPDU_S_WAIT_CLA); set_tpdu_state(ch, TPDU_S_WAIT_CLA);
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
break; break;
case ISO_S_IN_ATR:
case ISO_S_IN_PTS: case ISO_S_IN_PTS:
case ISO_S_IN_TPDU: case ISO_S_IN_TPDU:
/* do nothing */ /* do nothing */
@@ -311,12 +357,80 @@ static void card_set_state(struct card_handle *ch,
} }
} }
/**********************************************************************
* ATR handling
**********************************************************************/
/*! Transmit ATR data to reader
* @param[in] ch card interface connected to reader
* @return numbers of bytes transmitted
*/
static int tx_byte_atr(struct card_handle *ch)
{
if (NULL == ch) {
TRACE_ERROR("ATR TX: no card handle provided\n\r");
return 0;
}
if (ISO_S_IN_ATR != ch->state) {
TRACE_ERROR("%u: ATR TX: no in ATR state\n\r", ch->num);
return 0;
}
/* Transmit ATR */
if (ch->atr.idx < ch->atr.len) {
uint8_t byte = ch->atr.atr[ch->atr.idx++];
card_emu_uart_tx(ch->uart_chan, byte);
return 1;
} else { /* The ATR has been completely transmitted */
/* search for TC2 to updated WI */
ch->wi = ISO7816_3_DEFAULT_WI;
if (ch->atr.len >= 2 && ch->atr.atr[1] & 0xf0) { /* Y1 has some data */
uint8_t atr_td1 = 2;
if (ch->atr.atr[1] & 0x10) { /* TA1 is present */
atr_td1++;
}
if (ch->atr.atr[1] & 0x20) { /* TB1 is present */
atr_td1++;
}
if (ch->atr.atr[1] & 0x40) { /* TC1 is present */
atr_td1++;
}
if (ch->atr.atr[1] & 0x80) { /* TD1 is present */
if (ch->atr.len > atr_td1 && ch->atr.atr[atr_td1] & 0xf0) { /* Y2 has some data */
uint8_t atr_tc2 = atr_td1+1;
if (ch->atr.atr[atr_td1] & 0x10) { /* TA2 is present */
atr_tc2++;
}
if (ch->atr.atr[atr_td1] & 0x20) { /* TB2 is present */
atr_tc2++;
}
if (ch->atr.atr[atr_td1] & 0x40) { /* TC2 is present */
if (ch->atr.len > atr_tc2 && ch->atr.atr[atr_tc2]) { /* TC2 encodes WI */
ch->wi = ch->atr.atr[atr_tc2]; /* set WI */
}
}
}
}
}
/* update waiting time (see ISO 7816-3 10.2) */
ch->waiting_time = ch->wi * 960 * ch->fi;
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* go to next state */
card_set_state(ch, ISO_S_WAIT_TPDU);
return 0;
}
/* return number of bytes transmitted */
return 1;
}
/********************************************************************** /**********************************************************************
* PTS / PPS handling * PTS / PPS handling
**********************************************************************/ **********************************************************************/
/* Update the ATR sub-state */ /* Update the PTS sub-state */
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss) static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
{ {
TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n", TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n",
@@ -502,37 +616,33 @@ static unsigned int t0_num_data_bytes(uint8_t p3, int reader_to_card)
/* add a just-received TPDU byte (from reader) to USB buffer */ /* add a just-received TPDU byte (from reader) to USB buffer */
static void add_tpdu_byte(struct card_handle *ch, uint8_t byte) static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
{ {
struct req_ctx *rctx; struct msgb *msg;
struct cardemu_usb_msg_rx_data *rd; struct cardemu_usb_msg_rx_data *rd;
unsigned int num_data_bytes = t0_num_data_bytes(ch->tpdu.hdr[_P3], 0); unsigned int num_data_bytes = t0_num_data_bytes(ch->tpdu.hdr[_P3], 0);
/* ensure we have a buffer */ /* ensure we have a buffer */
if (!ch->uart_rx_ctx) { if (!ch->uart_rx_msg) {
rctx = ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY); msg = ch->uart_rx_msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
if (!ch->uart_rx_ctx) { SIMTRACE_MSGT_DO_CEMU_RX_DATA);
if (!ch->uart_rx_msg) {
TRACE_ERROR("%u: Received UART byte but ENOMEM\r\n", TRACE_ERROR("%u: Received UART byte but ENOMEM\r\n",
ch->num); ch->num);
return; return;
} }
rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data; msgb_put(msg, sizeof(*rd));
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
rctx->tot_len = sizeof(*rd);
rctx->idx = 0;
} else } else
rctx = ch->uart_rx_ctx; msg = ch->uart_rx_msg;
rd = (struct cardemu_usb_msg_rx_data *) rctx->data; rd = (struct cardemu_usb_msg_rx_data *) msg->l2h;
msgb_put_u8(msg, byte);
rd->data[rctx->idx++] = byte;
rctx->tot_len++;
/* check if the buffer is full. If so, send it */ /* check if the buffer is full. If so, send it */
if (rctx->tot_len >= sizeof(*rd) + num_data_bytes) { if (msgb_l2len(msg) >= sizeof(*rd) + num_data_bytes) {
rd->flags |= CEMU_DATA_F_FINAL; rd->flags |= CEMU_DATA_F_FINAL;
flush_rx_buffer(ch); flush_rx_buffer(ch);
/* We need to transmit the SW now, */ /* We need to transmit the SW now, */
set_tpdu_state(ch, TPDU_S_WAIT_TX); set_tpdu_state(ch, TPDU_S_WAIT_TX);
} else if (rctx->tot_len >= rctx->size) } else if (msgb_tailroom(msg) <= 0)
flush_rx_buffer(ch); flush_rx_buffer(ch);
} }
@@ -590,8 +700,9 @@ static enum tpdu_state next_tpdu_state(struct card_handle *ch)
static void send_tpdu_header(struct card_handle *ch) static void send_tpdu_header(struct card_handle *ch)
{ {
struct req_ctx *rctx; struct msgb *msg;
struct cardemu_usb_msg_rx_data *rd; struct cardemu_usb_msg_rx_data *rd;
uint8_t *cur;
TRACE_INFO("%u: %s: %02x %02x %02x %02x %02x\r\n", TRACE_INFO("%u: %s: %02x %02x %02x %02x %02x\r\n",
ch->num, __func__, ch->num, __func__,
@@ -600,32 +711,30 @@ static void send_tpdu_header(struct card_handle *ch)
ch->tpdu.hdr[4]); ch->tpdu.hdr[4]);
/* if we already/still have a context, send it off */ /* if we already/still have a context, send it off */
if (ch->uart_rx_ctx) { if (ch->uart_rx_msg) {
TRACE_DEBUG("%u: have old buffer\r\n", ch->num); TRACE_DEBUG("%u: have old buffer\r\n", ch->num);
if (ch->uart_rx_ctx->idx) { if (msgb_l2len(ch->uart_rx_msg)) {
TRACE_DEBUG("%u: flushing old buffer\r\n", ch->num); TRACE_DEBUG("%u: flushing old buffer\r\n", ch->num);
flush_rx_buffer(ch); flush_rx_buffer(ch);
} }
} else { }
TRACE_DEBUG("%u: allocating new buffer\r\n", ch->num); TRACE_DEBUG("%u: allocating new buffer\r\n", ch->num);
/* ensure we have a new buffer */ /* ensure we have a new buffer */
ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY); ch->uart_rx_msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
if (!ch->uart_rx_ctx) { SIMTRACE_MSGT_DO_CEMU_RX_DATA);
if (!ch->uart_rx_msg) {
TRACE_ERROR("%u: %s: ENOMEM\r\n", ch->num, __func__); TRACE_ERROR("%u: %s: ENOMEM\r\n", ch->num, __func__);
return; return;
} }
} msg = ch->uart_rx_msg;
rctx = ch->uart_rx_ctx; rd = (struct cardemu_usb_msg_rx_data *) msgb_put(msg, sizeof(*rd));
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
/* initializ header */ /* initialize header */
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
rd->flags = CEMU_DATA_F_TPDU_HDR; rd->flags = CEMU_DATA_F_TPDU_HDR;
rctx->tot_len = sizeof(*rd) + sizeof(ch->tpdu.hdr);
rctx->idx = sizeof(ch->tpdu.hdr);
/* copy TPDU header to data field */ /* copy TPDU header to data field */
memcpy(rd->data, ch->tpdu.hdr, sizeof(ch->tpdu.hdr)); cur = msgb_put(msg, sizeof(ch->tpdu.hdr));
memcpy(cur, ch->tpdu.hdr, sizeof(ch->tpdu.hdr));
/* rd->data_len is set in flush_rx_buffer() */ /* rd->data_len is set in flush_rx_buffer() */
flush_rx_buffer(ch); flush_rx_buffer(ch);
@@ -674,37 +783,35 @@ process_byte_tpdu(struct card_handle *ch, uint8_t byte)
/* tx a single byte to be transmitted to the reader */ /* tx a single byte to be transmitted to the reader */
static int tx_byte_tpdu(struct card_handle *ch) static int tx_byte_tpdu(struct card_handle *ch)
{ {
struct req_ctx *rctx; struct msgb *msg;
struct cardemu_usb_msg_tx_data *td; struct cardemu_usb_msg_tx_data *td;
uint8_t byte; uint8_t byte;
/* ensure we are aware of any data that might be pending for /* ensure we are aware of any data that might be pending for
* transmit */ * transmit */
if (!ch->uart_tx_ctx) { if (!ch->uart_tx_msg) {
/* uart_tx_queue is filled from main loop, so no need /* uart_tx_queue is filled from main loop, so no need
* for irq-safe operations */ * for irq-safe operations */
if (llist_empty(&ch->uart_tx_queue)) if (llist_empty(&ch->uart_tx_queue))
return 0; return 0;
/* dequeue first at head */ /* dequeue first at head */
ch->uart_tx_ctx = llist_entry(ch->uart_tx_queue.next, ch->uart_tx_msg = msgb_dequeue(&ch->uart_tx_queue);
struct req_ctx, list); ch->uart_tx_msg->l1h = ch->uart_tx_msg->head;
llist_del(&ch->uart_tx_ctx->list); ch->uart_tx_msg->l2h = ch->uart_tx_msg->l1h + sizeof(struct simtrace_msg_hdr);
req_ctx_set_state(ch->uart_tx_ctx, RCTX_S_UART_TX_BUSY); msg = ch->uart_tx_msg;
/* remove the header */
/* start with index zero */ msgb_pull(msg, sizeof(struct simtrace_msg_hdr) + sizeof(*td));
ch->uart_tx_ctx->idx = 0;
} }
rctx = ch->uart_tx_ctx; msg = ch->uart_tx_msg;
td = (struct cardemu_usb_msg_tx_data *) rctx->data; td = (struct cardemu_usb_msg_tx_data *) msg->l2h;
/* take the next pending byte out of the rctx */ /* take the next pending byte out of the msgb */
byte = td->data[rctx->idx++]; byte = msgb_pull_u8(msg);
card_emu_uart_tx(ch->uart_chan, byte); card_emu_uart_tx(ch->uart_chan, byte);
/* this must happen _after_ the byte has been transmittd */ /* this must happen _after_ the byte has been transmitted */
switch (ch->tpdu.state) { switch (ch->tpdu.state) {
case TPDU_S_WAIT_PB: case TPDU_S_WAIT_PB:
/* if we just transmitted the procedure byte, we need to decide /* if we just transmitted the procedure byte, we need to decide
@@ -719,8 +826,7 @@ static int tx_byte_tpdu(struct card_handle *ch)
} }
/* check if the buffer has now been fully transmitted */ /* check if the buffer has now been fully transmitted */
if ((rctx->idx >= td->data_len) || if (msgb_length(msg) == 0) {
(td->data + rctx->idx >= rctx->data + rctx->tot_len)) {
if (td->flags & CEMU_DATA_F_PB_AND_RX) { if (td->flags & CEMU_DATA_F_PB_AND_RX) {
/* we have just sent the procedure byte and now /* we have just sent the procedure byte and now
* need to continue receiving */ * need to continue receiving */
@@ -733,8 +839,8 @@ static int tx_byte_tpdu(struct card_handle *ch)
card_set_state(ch, ISO_S_WAIT_TPDU); card_set_state(ch, ISO_S_WAIT_TPDU);
} }
} }
req_ctx_set_state(rctx, RCTX_S_FREE); usb_buf_free(msg);
ch->uart_tx_ctx = NULL; ch->uart_tx_msg = NULL;
} }
return 1; return 1;
@@ -752,14 +858,6 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
ch->stats.rx_bytes++; ch->stats.rx_bytes++;
switch (ch->state) { switch (ch->state) {
case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST:
case ISO_S_WAIT_ATR:
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
"%u\r\n", ch->num, ch->state);
/* we shouldn't receive any data from the reader yet! */
break;
case ISO_S_WAIT_TPDU: case ISO_S_WAIT_TPDU:
if (byte == 0xff) { if (byte == 0xff) {
new_state = process_byte_pts(ch, byte); new_state = process_byte_pts(ch, byte);
@@ -773,6 +871,10 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
case ISO_S_IN_PTS: case ISO_S_IN_PTS:
new_state = process_byte_pts(ch, byte); new_state = process_byte_pts(ch, byte);
goto out_silent; goto out_silent;
default:
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
"%u\r\n", ch->num, ch->state);
break;
} }
out_silent: out_silent:
@@ -787,17 +889,7 @@ int card_emu_tx_byte(struct card_handle *ch)
switch (ch->state) { switch (ch->state) {
case ISO_S_IN_ATR: case ISO_S_IN_ATR:
if (ch->atr.idx < ch->atr.len) { rc = tx_byte_atr(ch);
uint8_t byte;
byte = ch->atr.atr[ch->atr.idx++];
rc = 1;
card_emu_uart_tx(ch->uart_chan, byte);
/* detect end of ATR */
if (ch->atr.idx >= ch->atr.len)
card_set_state(ch, ISO_S_WAIT_TPDU);
}
break; break;
case ISO_S_IN_PTS: case ISO_S_IN_PTS:
rc = tx_byte_pts(ch); rc = tx_byte_pts(ch);
@@ -836,17 +928,15 @@ void card_emu_have_new_uart_tx(struct card_handle *ch)
void card_emu_report_status(struct card_handle *ch) void card_emu_report_status(struct card_handle *ch)
{ {
struct req_ctx *rctx; struct msgb *msg;
struct cardemu_usb_msg_status *sts; struct cardemu_usb_msg_status *sts;
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY); msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM,
if (!rctx) SIMTRACE_MSGT_BD_CEMU_STATUS);
if (!msg)
return; return;
rctx->tot_len = sizeof(*sts); sts = (struct cardemu_usb_msg_status *) msgb_put(msg, sizeof(*sts));
sts = (struct cardemu_usb_msg_status *)rctx->data;
sts->hdr.msg_type = CEMU_USB_MSGT_DO_STATUS;
sts->hdr.msg_len = sizeof(*sts);
sts->flags = 0; sts->flags = 0;
if (ch->vcc_active) if (ch->vcc_active)
sts->flags |= CEMU_STATUS_F_VCC_PRESENT; sts->flags |= CEMU_STATUS_F_VCC_PRESENT;
@@ -860,8 +950,7 @@ void card_emu_report_status(struct card_handle *ch)
sts->wi = ch->wi; sts->wi = ch->wi;
sts->waiting_time = ch->waiting_time; sts->waiting_time = ch->waiting_time;
llist_add_tail(&rctx->list, &ch->usb_tx_queue); usb_buf_upd_len_and_submit(msg);
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
} }
/* hardware driver informs us that a card I/O signal has changed */ /* hardware driver informs us that a card I/O signal has changed */
@@ -895,9 +984,8 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
if (ch->vcc_active && ch->clocked) { if (ch->vcc_active && ch->clocked) {
/* enable the TC/ETU counter once reset has been released */ /* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan); tc_etu_enable(ch->tc_chan);
/* prepare to send the ATR */
card_set_state(ch, ISO_S_WAIT_ATR); card_set_state(ch, ISO_S_WAIT_ATR);
/* FIXME: wait 400 to 40k clock cycles before sending ATR */
card_set_state(ch, ISO_S_IN_ATR);
} }
} else if (active && !ch->in_reset) { } else if (active && !ch->in_reset) {
TRACE_INFO("%u: RST asserted\r\n", ch->num); TRACE_INFO("%u: RST asserted\r\n", ch->num);
@@ -918,7 +1006,15 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
ch->atr.len = len; ch->atr.len = len;
ch->atr.idx = 0; ch->atr.idx = 0;
/* FIXME: race condition with trasmitting ATR to reader? */ #if TRACE_LEVEL >= TRACE_LEVEL_INFO
uint8_t i;
TRACE_INFO("%u: ATR set: ", ch->num);
for (i = 0; i < ch->atr.len; i++) {
TRACE_INFO_WP("%02x ", atr[i]);
}
TRACE_INFO_WP("\n\r");
#endif
/* FIXME: race condition with transmitting ATR to reader? */
return 0; return 0;
} }
@@ -949,7 +1045,15 @@ void tc_etu_wtime_half_expired(void *handle)
void tc_etu_wtime_expired(void *handle) void tc_etu_wtime_expired(void *handle)
{ {
struct card_handle *ch = handle; struct card_handle *ch = handle;
switch (ch->state) {
case ISO_S_WAIT_ATR:
/* ISO 7816-3 6.2.1 time tc has passed, we can now send the ATR */
card_set_state(ch, ISO_S_IN_ATR);
break;
default:
TRACE_ERROR("%u: wtime_exp\r\n", ch->num); TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
break;
}
} }
/* shortest ATR found in smartcard_list.txt */ /* shortest ATR found in smartcard_list.txt */
@@ -957,7 +1061,8 @@ static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 };
static struct card_handle card_handles[NUM_SLOTS]; static struct card_handle card_handles[NUM_SLOTS];
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan) struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan,
uint8_t in_ep, uint8_t irq_ep)
{ {
struct card_handle *ch; struct card_handle *ch;
@@ -968,11 +1073,12 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
memset(ch, 0, sizeof(*ch)); memset(ch, 0, sizeof(*ch));
INIT_LLIST_HEAD(&ch->usb_tx_queue);
INIT_LLIST_HEAD(&ch->uart_tx_queue); INIT_LLIST_HEAD(&ch->uart_tx_queue);
/* initialize the card_handle with reasonabe defaults */ /* initialize the card_handle with reasonable defaults */
ch->num = slot_num; ch->num = slot_num;
ch->irq_ep = irq_ep;
ch->in_ep = in_ep;
ch->state = ISO_S_WAIT_POWER; ch->state = ISO_S_WAIT_POWER;
ch->vcc_active = 0; ch->vcc_active = 0;
ch->in_reset = 1; ch->in_reset = 1;

View File

@@ -83,8 +83,6 @@
/// Driver structure for an CCID device /// Driver structure for an CCID device
typedef struct { typedef struct {
/// Standard USB device driver instance
USBDDriver usbdDriver;
/// CCID message /// CCID message
S_ccid_bulk_in_header sCcidMessage; S_ccid_bulk_in_header sCcidMessage;
/// CCID command /// CCID command
@@ -849,7 +847,6 @@ static void CCIDCommandDispatcher( void *pArg, uint8_t status, uint32_t transfer
} }
#if 0
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// SETUP request handler for a CCID device /// SETUP request handler for a CCID device
/// \param pRequest Pointer to a USBGenericRequest instance /// \param pRequest Pointer to a USBGenericRequest instance
@@ -890,7 +887,7 @@ static void CCID_RequestHandler(const USBGenericRequest *pRequest)
else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) { else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
// Forward request to the standard handler // Forward request to the standard handler
USBDDriver_RequestHandler(&(ccidDriver.usbdDriver), pRequest); USBDDriver_RequestHandler(USBD_GetDriver(), pRequest);
} }
else { else {
@@ -916,7 +913,6 @@ void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
CCID_RequestHandler(request); CCID_RequestHandler(request);
} }
#endif #endif
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -1,3 +1,19 @@
/* UART print output
*
* 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 <stdio.h> #include <stdio.h>
#include "uart_console.h" #include "uart_console.h"
@@ -10,6 +26,19 @@ int fputc(int c, FILE *stream)
int fputs(const char *s, FILE *stream) int fputs(const char *s, FILE *stream)
{ {
while (*s != '\0') while (*s != '\0')
UART_PutChar(*s++); fputc(*s++, stream);
return 0;
}
int fputc_sync(int c, FILE *stream)
{
UART_PutChar_Sync(c);
return c;
}
int fputs_sync(const char *s, FILE *stream)
{
while (*s != '\0')
fputc_sync(*s++, stream);
return 0; return 0;
} }

View File

@@ -1,126 +1,189 @@
//#define TRACE_LEVEL 6 /* USB communication methods
*
* 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 "llist_irqsafe.h"
#include "usb_buf.h"
#include "utils.h"
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <errno.h> #include <errno.h>
#include "board.h" /***********************************************************************
#include "req_ctx.h" * USBD Integration API
#include "osmocom/core/linuxlist.h" ***********************************************************************/
#include "llist_irqsafe.h"
static volatile uint32_t usbep_in_progress[BOARD_USB_NUMENDPOINTS];
/* call-back after (successful?) transfer of a buffer */ /* call-back after (successful?) transfer of a buffer */
static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred, static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
uint32_t remaining) uint32_t remaining)
{ {
struct req_ctx *rctx = (struct req_ctx *) arg; struct msgb *msg = (struct msgb *) arg;
struct usb_buffered_ep *bep = msg->dst;
unsigned long x;
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, rctx->ep); TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
__disable_irq(); local_irq_save(x);
usbep_in_progress[rctx->ep]--; bep->in_progress--;
__enable_irq(); local_irq_restore(x);
TRACE_DEBUG("%u: in_progress=%d\n", rctx->ep, usbep_in_progress[rctx->ep]); TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress);
if (status != USBD_STATUS_SUCCESS) if (status != USBD_STATUS_SUCCESS)
TRACE_ERROR("%s error, status=%d\n", __func__, status); TRACE_ERROR("%s error, status=%d\n", __func__, status);
/* release request contxt to pool */ usb_buf_free(msg);
req_ctx_set_state(rctx, RCTX_S_FREE);
} }
int usb_refill_to_host(struct llist_head *queue, uint32_t ep) int usb_refill_to_host(uint8_t ep)
{ {
struct req_ctx *rctx; struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg;
unsigned long x;
int rc; int rc;
__disable_irq(); #if 0
if (usbep_in_progress[ep]) { if (bep->out_from_host) {
__enable_irq(); TRACE_ERROR("EP 0x%02x is not IN\r\n", bep->ep);
return -EINVAL;
}
#endif
local_irq_save(x);
if (bep->in_progress) {
local_irq_restore(x);
return 0; return 0;
} }
if (llist_empty(queue)) { if (llist_empty(&bep->queue)) {
__enable_irq(); local_irq_restore(x);
return 0; return 0;
} }
usbep_in_progress[ep]++; bep->in_progress++;
rctx = llist_entry(queue->next, struct req_ctx, list); msg = msgb_dequeue(&bep->queue);
llist_del(&rctx->list);
__enable_irq(); local_irq_restore(x);
TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]); TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress);
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
req_ctx_set_state(rctx, RCTX_S_USB_TX_BUSY); msg->dst = bep;
rctx->ep = ep;
rc = USBD_Write(ep, rctx->data, rctx->tot_len, rc = USBD_Write(ep, msgb_data(msg), msgb_length(msg),
(TransferCallback) &usb_write_cb, rctx); (TransferCallback) &usb_write_cb, msg);
if (rc != USBD_STATUS_SUCCESS) { if (rc != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error %x\n", __func__, rc); TRACE_ERROR("%s error %x\n", __func__, rc);
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING); /* re-insert to head of queue */
__disable_irq(); llist_add_irqsafe(&msg->list, &bep->queue);
usbep_in_progress[ep]--; local_irq_save(x);
__enable_irq(); bep->in_progress--;
TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]); local_irq_restore(x);
TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress);
return 0; return 0;
} }
return 1; return 1;
} }
/* call-back after (successful?) transfer of a buffer */
static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
uint32_t remaining) uint32_t remaining)
{ {
struct req_ctx *rctx = (struct req_ctx *) arg; struct msgb *msg = (struct msgb *) arg;
struct llist_head *queue = (struct llist_head *) usbep_in_progress[rctx->ep]; struct usb_buffered_ep *bep = msg->dst;
TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__, TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__,
rctx->ep, transferred, queue); bep->ep, transferred, &bep->queue);
usbep_in_progress[rctx->ep] = 0; bep->in_progress = 0;
if (status != USBD_STATUS_SUCCESS) { if (status != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error, status=%d\n", __func__, status); TRACE_ERROR("%s error, status=%d\n", __func__, status);
/* release request contxt to pool */ usb_buf_free(msg);
req_ctx_put(rctx);
return; return;
} }
rctx->tot_len = transferred; msgb_put(msg, transferred);
req_ctx_set_state(rctx, RCTX_S_MAIN_PROCESSING); llist_add_tail_irqsafe(&msg->list, &bep->queue);
llist_add_tail_irqsafe(&rctx->list, queue);
} }
int usb_refill_from_host(struct llist_head *queue, int ep) int usb_refill_from_host(uint8_t ep)
{ {
struct req_ctx *rctx; struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg;
unsigned long x;
int rc; int rc;
if (usbep_in_progress[ep]) #if 0
if (!bep->out_from_host) {
TRACE_ERROR("EP 0x%02x is not OUT\r\n", bep->ep);
return -EINVAL;
}
#endif
if (bep->in_progress)
return 0; return 0;
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep); TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_USB_RX_BUSY); msg = usb_buf_alloc(bep->ep);
if (!rctx) if (!msg)
return -ENOMEM; return -ENOMEM;
msg->dst = bep;
msg->l1h = msg->head;
rctx->ep = ep; bep->in_progress = 1;
usbep_in_progress[ep] = (uint32_t) queue;
rc = USBD_Read(ep, rctx->data, rctx->size,
(TransferCallback) &usb_read_cb, rctx);
rc = USBD_Read(ep, msg->head, msgb_tailroom(msg),
(TransferCallback) &usb_read_cb, msg);
if (rc != USBD_STATUS_SUCCESS) { if (rc != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error %x\n", __func__, rc); TRACE_ERROR("%s error %d\n", __func__, rc);
req_ctx_put(rctx); usb_buf_free(msg);
usbep_in_progress[ep] = 0; bep->in_progress = 0;
return 0;
} }
return 1; return 1;
} }
int usb_drain_queue(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg;
unsigned long x;
int ret = 0;
/* wait until no transfers are in progress anymore and block
* further interrupts */
while (1) {
local_irq_save(x);
if (!bep->in_progress) {
break;
}
local_irq_restore(x);
/* retry */
}
/* free all queued msgbs */
while ((msg = msgb_dequeue(&bep->queue))) {
usb_buf_free(msg);
ret++;
}
/* re-enable interrupts and return number of free'd msgbs */
local_irq_restore(x);
return ret;
}

View File

@@ -90,6 +90,7 @@ uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart)
/* Wait USART ready for reception */ /* Wait USART ready for reception */
while( ((us_base->US_CSR & US_CSR_RXRDY) == 0) ) { while( ((us_base->US_CSR & US_CSR_RXRDY) == 0) ) {
WDT_Restart(WDT);
if(timeout++ > 12000 * (BOARD_MCK/1000000)) { if(timeout++ > 12000 * (BOARD_MCK/1000000)) {
TRACE_WARNING("TimeOut\n\r"); TRACE_WARNING("TimeOut\n\r");
return( 0 ); return( 0 );
@@ -139,8 +140,8 @@ uint32_t ISO7816_SendChar( uint8_t CharToSend, Usart_info *usart )
while((us_base->US_CSR & (US_CSR_TXRDY)) == 0) { while((us_base->US_CSR & (US_CSR_TXRDY)) == 0) {
i++; i++;
if (!(i%1000000)) { if (!(i%1000000)) {
printf("s: %x ", us_base->US_CSR); printf("s: %lx ", us_base->US_CSR);
printf("s: %x\r\n", us_base->US_RHR & 0xFF); printf("s: %lx\r\n", us_base->US_RHR & 0xFF);
us_base->US_CR = US_CR_RSTTX; us_base->US_CR = US_CR_RSTTX;
us_base->US_CR = US_CR_RSTRX; us_base->US_CR = US_CR_RSTRX;
} }

View File

@@ -1,5 +1,6 @@
/* ISO7816-3 Fi/Di tables + computation */ /* ISO7816-3 Fi/Di tables + computation
/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de> *
* (C) 2010-2015 by Harald Welte <laforge@gnumonks.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -13,10 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
*/ */
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
@@ -24,13 +23,13 @@
#include "iso7816_fidi.h" #include "iso7816_fidi.h"
/* Table 7 of ISO 7816-3:2006 */ /* Table 7 of ISO 7816-3:2006 */
static const uint16_t fi_table[] = { const uint16_t fi_table[] = {
372, 372, 558, 744, 1116, 1488, 1860, 0, 372, 372, 558, 744, 1116, 1488, 1860, 0,
0, 512, 768, 1024, 1536, 2048, 0, 0 0, 512, 768, 1024, 1536, 2048, 0, 0
}; };
/* Table 8 from ISO 7816-3:2006 */ /* Table 8 from ISO 7816-3:2006 */
static const uint8_t di_table[] = { const uint8_t di_table[] = {
0, 1, 2, 4, 8, 16, 32, 64, 0, 1, 2, 4, 8, 16, 32, 64,
12, 20, 2, 4, 8, 16, 32, 64, 12, 20, 2, 4, 8, 16, 32, 64,
}; };

View File

@@ -1,19 +1,42 @@
//#define TRACE_LEVEL 6 /* card emulation mode
*
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 "board.h"
#include "boardver_adc.h"
#include "simtrace.h" #include "simtrace.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "card_emu.h" #include "card_emu.h"
#include "iso7816_fidi.h" #include "iso7816_fidi.h"
#include "utils.h" #include "utils.h"
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include "llist_irqsafe.h" #include "llist_irqsafe.h"
#include "req_ctx.h" #include "usb_buf.h"
#include "cardemu_prot.h" #include "simtrace_usb.h"
#include "simtrace_prot.h"
#include "sim_switch.h"
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__) #define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
#ifdef PINS_CARDSIM
static const Pin pins_cardsim[] = PINS_CARDSIM; static const Pin pins_cardsim[] = PINS_CARDSIM;
#endif
/* UART pins */ /* UART pins */
static const Pin pins_usim1[] = {PINS_USIM1}; static const Pin pins_usim1[] = {PINS_USIM1};
@@ -27,7 +50,7 @@ static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
#endif #endif
struct cardem_inst { struct cardem_inst {
uint32_t num; unsigned int num;
struct card_handle *ch; struct card_handle *ch;
struct llist_head usb_out_queue; struct llist_head usb_out_queue;
struct ringbuf rb; struct ringbuf rb;
@@ -41,7 +64,7 @@ struct cardem_inst {
uint32_t vcc_uv_last; uint32_t vcc_uv_last;
}; };
static struct cardem_inst cardem_inst[] = { struct cardem_inst cardem_inst[] = {
{ {
.num = 0, .num = 0,
.usart_info = { .usart_info = {
@@ -49,10 +72,12 @@ static struct cardem_inst cardem_inst[] = {
.id = ID_USART1, .id = ID_USART1,
.state = USART_RCV .state = USART_RCV
}, },
.ep_out = PHONE_DATAOUT, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
.ep_in = PHONE_DATAIN, .ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
.ep_int = PHONE_INT, .ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
#ifdef PIN_SET_USIM1_PRES
.pin_insert = PIN_SET_USIM1_PRES, .pin_insert = PIN_SET_USIM1_PRES,
#endif
}, },
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
{ {
@@ -62,26 +87,24 @@ static struct cardem_inst cardem_inst[] = {
.id = ID_USART0, .id = ID_USART0,
.state = USART_RCV .state = USART_RCV
}, },
.ep_out = CARDEM_USIM2_DATAOUT, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
.ep_in = CARDEM_USIM2_DATAIN, .ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
.ep_int = CARDEM_USIM2_INT, .ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
#ifdef PIN_SET_USIM2_PRES
.pin_insert = PIN_SET_USIM2_PRES, .pin_insert = PIN_SET_USIM2_PRES,
#endif
}, },
#endif #endif
}; };
static Usart *get_usart_by_chan(uint8_t uart_chan) static Usart *get_usart_by_chan(uint8_t uart_chan)
{ {
switch (uart_chan) { if (uart_chan < ARRAY_SIZE(cardem_inst)) {
case 0: return cardem_inst[uart_chan].usart_info.base;
return USART1; } else {
#ifdef CARDEMU_SECOND_UART
case 1:
return USART0;
#endif
}
return NULL; return NULL;
} }
}
/*********************************************************************** /***********************************************************************
* Call-Backs from card_emu.c * Call-Backs from card_emu.c
@@ -94,7 +117,7 @@ static void wait_tx_idle(Usart *usart)
/* wait until last char has been fully transmitted */ /* wait until last char has been fully transmitted */
while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) { while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
if (!(i%1000000)) { if (!(i%1000000)) {
TRACE_ERROR("s: %x \r\n", usart->US_CSR); TRACE_ERROR("s: %lx \r\n", usart->US_CSR);
} }
i++; i++;
} }
@@ -151,7 +174,7 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
int i = 1; int i = 1;
while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) { while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
if (!(i%1000000)) { if (!(i%1000000)) {
TRACE_ERROR("%u: s: %x %02X\r\n", TRACE_ERROR("%u: s: %lx %02lX\r\n",
uart_chan, usart->US_CSR, uart_chan, usart->US_CSR,
usart->US_RHR & 0xFF); usart->US_RHR & 0xFF);
usart->US_CR = US_CR_RSTTX; usart->US_CR = US_CR_RSTTX;
@@ -178,7 +201,8 @@ static void usart_irq_rx(uint8_t inst_num)
if (csr & US_CSR_RXRDY) { if (csr & US_CSR_RXRDY) {
byte = (usart->US_RHR) & 0xFF; byte = (usart->US_RHR) & 0xFF;
rbuf_write(&ci->rb, byte); if (rbuf_write(&ci->rb, byte) < 0)
TRACE_ERROR("rbuf overrun\r\n");
} }
if (csr & US_CSR_TXRDY) { if (csr & US_CSR_TXRDY) {
@@ -189,7 +213,7 @@ static void usart_irq_rx(uint8_t inst_num)
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE| if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) { US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
TRACE_ERROR("%u e 0x%x st: 0x%x\n", ci->num, byte, csr); TRACE_ERROR("%u e 0x%x st: 0x%lx\n", ci->num, byte, csr);
} }
} }
@@ -217,6 +241,20 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
return 0; return 0;
} }
/* call-back from card_emu.c to force a USART interrupt */
void card_emu_uart_interrupt(uint8_t uart_chan)
{
Usart *usart = get_usart_by_chan(uart_chan);
if (!usart) {
return;
}
if (USART0 == usart) {
NVIC_SetPendingIRQ(USART0_IRQn);
} else if (USART1 == usart) {
NVIC_SetPendingIRQ(USART1_IRQn);
}
}
/*********************************************************************** /***********************************************************************
* ADC for VCC voltage detection * ADC for VCC voltage detection
***********************************************************************/ ***********************************************************************/
@@ -270,7 +308,6 @@ static int card_vcc_adc_init(void)
return 0; return 0;
} }
#define UV_PER_LSB ((3300 * 1000) / 4096)
#define VCC_UV_THRESH_1V8 1500000 #define VCC_UV_THRESH_1V8 1500000
#define VCC_UV_THRESH_3V 2800000 #define VCC_UV_THRESH_3V 2800000
@@ -290,12 +327,6 @@ static void process_vcc_adc(struct cardem_inst *ci)
ci->vcc_uv_last = ci->vcc_uv; ci->vcc_uv_last = ci->vcc_uv;
} }
static uint32_t adc2uv(uint16_t adc)
{
uint32_t uv = (uint32_t) adc * UV_PER_LSB;
return uv;
}
void ADC_IrqHandler(void) void ADC_IrqHandler(void)
{ {
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
@@ -371,7 +402,9 @@ void mode_cardemu_init(void)
TRACE_ENTRY(); TRACE_ENTRY();
#ifdef PINS_CARDSIM
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim)); PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
#endif
#ifdef DETECT_VCC_BY_ADC #ifdef DETECT_VCC_BY_ADC
card_vcc_adc_init(); card_vcc_adc_init();
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
@@ -387,7 +420,8 @@ void mode_cardemu_init(void)
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
PIO_EnableIt(&pin_usim1_vcc); PIO_EnableIt(&pin_usim1_vcc);
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[0].ch = card_emu_init(0, 2, 0); cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM1_INT);
sim_switch_use_physical(0, 1);
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue); INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
@@ -401,8 +435,10 @@ void mode_cardemu_init(void)
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler); PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
PIO_EnableIt(&pin_usim2_vcc); PIO_EnableIt(&pin_usim2_vcc);
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[1].ch = card_emu_init(1, 0, 1); cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM2_INT);
sim_switch_use_physical(1, 1);
#endif /* CARDEMU_SECOND_UART */ #endif /* CARDEMU_SECOND_UART */
} }
/* called if config is deactivated */ /* called if config is deactivated */
@@ -411,7 +447,7 @@ void mode_cardemu_exit(void)
TRACE_ENTRY(); TRACE_ENTRY();
/* FIXME: stop tc_fdt */ /* FIXME: stop tc_fdt */
/* FIXME: release all rctx, unlink them from any queue */ /* FIXME: release all msg, unlink them from any queue */
PIO_DisableIt(&pin_usim1_rst); PIO_DisableIt(&pin_usim1_rst);
PIO_DisableIt(&pin_usim1_vcc); PIO_DisableIt(&pin_usim1_vcc);
@@ -431,84 +467,209 @@ void mode_cardemu_exit(void)
} }
/* handle a single USB command as received from the USB host */ /* handle a single USB command as received from the USB host */
static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci) static void dispatch_usb_command_generic(struct msgb *msg, struct cardem_inst *ci)
{ {
struct cardemu_usb_msg_hdr *hdr; struct simtrace_msg_hdr *hdr;
hdr = (struct simtrace_msg_hdr *) msg->l1h;
switch (hdr->msg_type) {
case SIMTRACE_CMD_BD_BOARD_INFO:
break;
default:
break;
}
usb_buf_free(msg);
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci)
{
struct simtrace_msg_hdr *hdr;
struct cardemu_usb_msg_set_atr *atr; struct cardemu_usb_msg_set_atr *atr;
struct cardemu_usb_msg_cardinsert *cardins; struct cardemu_usb_msg_cardinsert *cardins;
struct llist_head *queue; struct llist_head *queue;
hdr = (struct cardemu_usb_msg_hdr *) rctx->data; hdr = (struct simtrace_msg_hdr *) msg->l1h;
switch (hdr->msg_type) { switch (hdr->msg_type) {
case CEMU_USB_MSGT_DT_TX_DATA: case SIMTRACE_MSGT_DT_CEMU_TX_DATA:
queue = card_emu_get_uart_tx_queue(ci->ch); queue = card_emu_get_uart_tx_queue(ci->ch);
req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING); llist_add_tail(&msg->list, queue);
llist_add_tail(&rctx->list, queue);
card_emu_have_new_uart_tx(ci->ch); card_emu_have_new_uart_tx(ci->ch);
break; break;
case CEMU_USB_MSGT_DT_SET_ATR: case SIMTRACE_MSGT_DT_CEMU_SET_ATR:
atr = (struct cardemu_usb_msg_set_atr *) hdr; atr = (struct cardemu_usb_msg_set_atr *) msg->l2h;
card_emu_set_atr(ci->ch, atr->atr, atr->atr_len); card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
req_ctx_put(rctx); usb_buf_free(msg);
break; break;
case CEMU_USB_MSGT_DT_CARDINSERT: case SIMTRACE_MSGT_DT_CEMU_CARDINSERT:
cardins = (struct cardemu_usb_msg_cardinsert *) hdr; cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h;
if (!ci->pin_insert.pio) {
TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n",
ci->num, cardins->card_insert ? "INSERTED" : "REMOVED");
break;
}
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num, TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
cardins->card_insert ? "INSERTED" : "REMOVED"); cardins->card_insert ? "INSERTED" : "REMOVED");
if (cardins->card_insert) if (cardins->card_insert)
PIO_Set(&ci->pin_insert); PIO_Set(&ci->pin_insert);
else else
PIO_Clear(&ci->pin_insert); PIO_Clear(&ci->pin_insert);
req_ctx_put(rctx); usb_buf_free(msg);
break; break;
case CEMU_USB_MSGT_DT_GET_STATUS: case SIMTRACE_MSGT_BD_CEMU_STATUS:
card_emu_report_status(ci->ch); card_emu_report_status(ci->ch);
usb_buf_free(msg);
break; break;
case CEMU_USB_MSGT_DT_GET_STATS: case SIMTRACE_MSGT_BD_CEMU_STATS:
default: default:
/* FIXME */ /* FIXME: Send Error */
req_ctx_put(rctx); usb_buf_free(msg);
break; break;
} }
} }
static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci) #ifdef PINS_PERST
#include "wwan_perst.h"
#endif
static int usb_command_modem_reset(struct msgb *msg, struct cardem_inst *ci)
{ {
struct req_ctx *segm; struct st_modem_reset *mr = (struct st_modem_reset *) msg->l2h;
struct cardemu_usb_msg_hdr *mh;
int i = 0; if (msgb_l2len(msg) < sizeof(*mr))
return -1;
switch (mr->asserted) {
#ifdef PINS_PERST
case 0:
wwan_perst_set(ci->num, 0);
break;
case 1:
wwan_perst_set(ci->num, 1);
break;
case 2:
wwan_perst_do_reset_pulse(ci->num, mr->pulse_duration_msec);
break;
#endif
default:
return -1;
}
return 0;
}
static int usb_command_sim_select(struct msgb *msg, struct cardem_inst *ci)
{
struct st_modem_sim_select *mss = (struct st_modem_sim_select *) 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)
{
struct simtrace_msg_hdr *hdr;
hdr = (struct simtrace_msg_hdr *) msg->l1h;
switch (hdr->msg_type) {
case SIMTRACE_MSGT_DT_MODEM_RESET:
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;
default:
break;
}
usb_buf_free(msg);
}
/* handle a single USB command as received from the USB host */
static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
{
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h;
if (msgb_length(msg) < sizeof(*sh)) {
/* FIXME: Error */
usb_buf_free(msg);
return;
}
msg->l2h = msg->l1h + sizeof(*sh);
switch (sh->msg_class) {
case SIMTRACE_MSGC_GENERIC:
dispatch_usb_command_generic(msg, ci);
break;
case SIMTRACE_MSGC_CARDEM:
dispatch_usb_command_cardem(msg, ci);
break;
case SIMTRACE_MSGC_MODEM:
/* FIXME: Find out why this fails if used for !=
* MSGC_MODEM ?!? */
dispatch_usb_command_modem(msg, ci);
break;
default:
/* FIXME: Send Error */
usb_buf_free(msg);
break;
}
}
static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
{
struct msgb *segm;
struct simtrace_msg_hdr *mh;
/* check if we have multiple concatenated commands in /* check if we have multiple concatenated commands in
* one message. USB endpoints are streams that don't * one message. USB endpoints are streams that don't
* preserve the message boundaries */ * preserve the message boundaries */
mh = (struct cardemu_usb_msg_hdr *) rctx->data; mh = (struct simtrace_msg_hdr *) msg->data;
if (mh->msg_len == rctx->tot_len) { if (mh->msg_len == msgb_length(msg)) {
/* fast path: only one message in buffer */ /* fast path: only one message in buffer */
dispatch_usb_command(rctx, ci); dispatch_usb_command(msg, ci);
return; return;
} }
/* slow path: iterate over list of messages, allocating one new /* slow path: iterate over list of messages, allocating one new
* reqe_ctx per segment */ * reqe_ctx per segment */
for (mh = (struct cardemu_usb_msg_hdr *) rctx->data; while (1) {
(uint8_t *)mh < rctx->data + rctx->tot_len; mh = (struct simtrace_msg_hdr *) msg->data;
mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING); segm = usb_buf_alloc(ci->ep_out);
if (!segm) { if (!segm) {
TRACE_ERROR("%u: ENOMEM during rctx segmentation\r\n", TRACE_ERROR("%u: ENOMEM during msg segmentation\r\n",
ci->num); ci->num);
break; break;
} }
segm->idx = 0;
segm->tot_len = mh->msg_len; if (mh->msg_len > msgb_length(msg)) {
memcpy(segm->data, mh, segm->tot_len); TRACE_ERROR("%u: Unexpected large message (%u bytes)\n",
ci->num, mh->msg_len);
usb_buf_free(segm);
} else {
uint8_t *cur = msgb_put(segm, mh->msg_len);
segm->l1h = segm->head;
memcpy(cur, mh, mh->msg_len);
dispatch_usb_command(segm, ci); dispatch_usb_command(segm, ci);
i++; }
/* pull this message */
msgb_pull(msg, mh->msg_len);
/* abort if we're done */
if (msgb_length(msg) <= 0)
break;
} }
/* release the master req_ctx, as all segments have been usb_buf_free(msg);
* processed now */
req_ctx_put(rctx);
} }
/* iterate over the queue of incoming USB commands and dispatch/execute /* iterate over the queue of incoming USB commands and dispatch/execute
@@ -517,7 +678,7 @@ static void process_any_usb_commands(struct llist_head *main_q,
struct cardem_inst *ci) struct cardem_inst *ci)
{ {
struct llist_head *lh; struct llist_head *lh;
struct req_ctx *rctx; struct msgb *msg;
int i; int i;
/* limit the number of iterations to 10, to ensure we don't get /* limit the number of iterations to 10, to ensure we don't get
@@ -527,8 +688,8 @@ static void process_any_usb_commands(struct llist_head *main_q,
lh = llist_head_dequeue_irqsafe(main_q); lh = llist_head_dequeue_irqsafe(main_q);
if (!lh) if (!lh)
break; break;
rctx = llist_entry(lh, struct req_ctx, list); msg = llist_entry(lh, struct msgb, list);
dispatch_received_rctx(rctx, ci); dispatch_received_msg(msg, ci);
} }
} }
@@ -554,19 +715,16 @@ void mode_cardemu_run(void)
//TRACE_ERROR("%uRx%02x\r\n", i, byte); //TRACE_ERROR("%uRx%02x\r\n", i, byte);
} }
queue = card_emu_get_usb_tx_queue(ci->ch); /* first try to send any pending messages on IRQ */
int usb_pending = llist_count(queue); usb_refill_to_host(ci->ep_int);
if (usb_pending != ci->usb_pending_old) {
TRACE_DEBUG("%u usb_pending=%d\r\n", /* then try to send any pending messages on IN */
i, usb_pending); usb_refill_to_host(ci->ep_in);
ci->usb_pending_old = usb_pending;
}
usb_refill_to_host(queue, ci->ep_in);
/* ensure we can handle incoming USB messages from the /* ensure we can handle incoming USB messages from the
* host */ * host */
queue = &ci->usb_out_queue; usb_refill_from_host(ci->ep_out);
usb_refill_from_host(queue, ci->ep_out); queue = usb_get_queue(ci->ep_out);
process_any_usb_commands(queue, ci); process_any_usb_commands(queue, ci);
} }
} }

View File

@@ -27,14 +27,15 @@
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#include "board.h"
#include "simtrace.h"
#ifdef HAVE_CCID #ifdef HAVE_CCID
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
#include "board.h"
#include <string.h> #include <string.h>
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@@ -125,6 +126,7 @@ static void ConfigureCardDetection(void)
*-----------------------------------------------------------------------------*/ *-----------------------------------------------------------------------------*/
extern CCIDDriverConfigurationDescriptors configurationDescriptorCCID; extern CCIDDriverConfigurationDescriptors configurationDescriptorCCID;
/* Called during USB enumeration after device is enumerated by host */
void CCID_configure(void) void CCID_configure(void)
{ {
CCIDDriver_Initialize(); CCIDDriver_Initialize();
@@ -132,6 +134,7 @@ void CCID_configure(void)
PIO_ConfigureIt(&pinSmartCard, ISR_PioSmartCard); PIO_ConfigureIt(&pinSmartCard, ISR_PioSmartCard);
} }
/* called when *different* configuration is set by host */
void CCID_exit(void) void CCID_exit(void)
{ {
PIO_DisableIt(&pinSmartCard); PIO_DisableIt(&pinSmartCard);
@@ -139,6 +142,7 @@ void CCID_exit(void)
USART_SetReceiverEnabled(usart_info.base, 0); USART_SetReceiverEnabled(usart_info.base, 0);
} }
/* called when *CCID* configuration is set by host */
void CCID_init(void) void CCID_init(void)
{ {
uint8_t pAtr[MAX_ATR_SIZE]; uint8_t pAtr[MAX_ATR_SIZE];
@@ -178,6 +182,7 @@ void CCID_init(void)
} }
} }
/* main (idle/busy) loop of this USB configuration */
void CCID_run(void) void CCID_run(void)
{ {

View File

@@ -1,196 +0,0 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "board.h"
#include <string.h>
/*------------------------------------------------------------------------------
* Internal definitions
*------------------------------------------------------------------------------*/
/** Maximum ucSize in bytes of the smartcard answer to a command.*/
#define MAX_ANSWER_SIZE 10
/** Maximum ATR ucSize in bytes.*/
#define MAX_ATR_SIZE 55
/** USB states */
/// Use for power management
#define STATE_IDLE 0
/// The USB device is in suspend state
#define STATE_SUSPEND 4
/// The USB device is in resume state
#define STATE_RESUME 5
extern volatile uint8_t timeout_occured;
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
/** USB state: suspend, resume, idle */
unsigned char USBState = STATE_IDLE;
/** ISO7816 pins */
static const Pin pinsISO7816_PHONE[] = { PINS_ISO7816_PHONE };
/** Bus switch pins */
#if DEBUG_PHONE_SNIFF
#warning "Debug phone sniff via logic analyzer is enabled"
// Logic analyzer probes are easier to attach to the SIM card slot
static const Pin pins_bus[] = { PINS_BUS_SNIFF };
#else
static const Pin pins_bus[] = { PINS_BUS_DEFAULT };
#endif
/** ISO7816 RST pin */
static uint8_t sim_inserted = 0;
static const Pin pPwr[] = {
/* Enable power converter 4.5-6V to 3.3V; low: off */
{SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT},
/* Enable second power converter: VCC_PHONE to VCC_SIM; high: off */
{VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
};
const Pin pinPhoneRST = PIN_ISO7816_RST_PHONE;
static struct Usart_info usart_info = {
.base = USART_PHONE,
.id = ID_USART_PHONE,
.state = USART_RCV,
};
/* ===================================================*/
/* Taken from iso7816_4.c */
/* ===================================================*/
/** Flip flop for send and receive char */
#define USART_SEND 0
#define USART_RCV 1
/*-----------------------------------------------------------------------------
* Internal variables
*-----------------------------------------------------------------------------*/
static uint8_t host_to_sim_buf[BUFLEN];
static bool change_fidi = false;
static void receive_from_host(void);
static void sendResponse_to_phone(uint8_t * pArg, uint8_t status,
uint32_t transferred, uint32_t remaining)
{
if (status != USBD_STATUS_SUCCESS) {
TRACE_ERROR("USB err status: %d (%s)\n", __FUNCTION__, status);
return;
}
TRACE_DEBUG("sendResp, stat: %X, trnsf: %x, rem: %x\n\r", status,
transferred, remaining);
TRACE_DEBUG("Resp: %x %x %x .. %x\n", host_to_sim_buf[0],
host_to_sim_buf[1], host_to_sim_buf[2],
host_to_sim_buf[transferred - 1]);
USART_SetReceiverEnabled(USART_PHONE, 0);
USART_SetTransmitterEnabled(USART_PHONE, 1);
uint32_t i = 0;
if (host_to_sim_buf[0] == 0xff) {
printf("Change FIDI detected\n");
// PTS command, change FIDI after command
i = 2;
change_fidi = true;
}
for (; i < transferred; i++) {
ISO7816_SendChar(host_to_sim_buf[i], &usart_info);
}
USART_SetTransmitterEnabled(USART_PHONE, 0);
USART_SetReceiverEnabled(USART_PHONE, 1);
if (change_fidi == true) {
printf("Change FIDI: %x\n", host_to_sim_buf[2]);
update_fidi(host_to_sim_buf[2]);
change_fidi = false;
}
receive_from_host();
}
static void receive_from_host()
{
int ret;
if ((ret = USBD_Read(PHONE_DATAOUT, &host_to_sim_buf,
sizeof(host_to_sim_buf),
(TransferCallback) &sendResponse_to_phone,
0)) == USBD_STATUS_SUCCESS) {
} else {
TRACE_ERROR("USB Err: %X\n", ret);
}
}
void Phone_configure(void)
{
PIO_ConfigureIt(&pinPhoneRST, ISR_PhoneRST);
NVIC_EnableIRQ(PIOA_IRQn);
}
void Phone_exit(void)
{
PIO_DisableIt(&pinPhoneRST);
NVIC_DisableIRQ(USART1_IRQn);
USART_DisableIt(USART_PHONE, US_IER_RXRDY);
USART_SetTransmitterEnabled(USART_PHONE, 0);
USART_SetReceiverEnabled(USART_PHONE, 0);
}
void Phone_init(void)
{
PIO_Configure(pinsISO7816_PHONE, PIO_LISTSIZE(pinsISO7816_PHONE));
PIO_Configure(pins_bus, PIO_LISTSIZE(pins_bus));
PIO_Configure(&pinPhoneRST, 1);
PIO_EnableIt(&pinPhoneRST);
ISO7816_Init(&usart_info, CLK_SLAVE);
USART_SetTransmitterEnabled(USART_PHONE, 0);
USART_SetReceiverEnabled(USART_PHONE, 1);
USART_EnableIt(USART_PHONE, US_IER_RXRDY);
NVIC_EnableIRQ(USART1_IRQn);
receive_from_host();
}
void Phone_run(void)
{
check_data_from_phone();
}

View File

@@ -0,0 +1,96 @@
/* Memory allocation library
*
* 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 <stdint.h>
#include "talloc.h"
#include "trace.h"
#include "utils.h"
#include <osmocom/core/utils.h>
#define NUM_RCTX_SMALL 10
#define RCTX_SIZE_SMALL 348
static uint8_t msgb_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL] __attribute__((aligned(sizeof(long))));
static uint8_t msgb_inuse[NUM_RCTX_SMALL];
void *_talloc_zero(const void *ctx, size_t size, const char *name)
{
unsigned int i;
unsigned long x;
local_irq_save(x);
if (size > RCTX_SIZE_SMALL) {
local_irq_restore(x);
TRACE_ERROR("%s() request too large(%d > %d)\r\n", __func__, size, RCTX_SIZE_SMALL);
return NULL;
}
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
if (!msgb_inuse[i]) {
uint8_t *out = msgb_data[i];
msgb_inuse[i] = 1;
memset(out, 0, size);
local_irq_restore(x);
return out;
}
}
local_irq_restore(x);
TRACE_ERROR("%s() out of memory!\r\n", __func__);
return NULL;
}
int _talloc_free(void *ptr, const char *location)
{
unsigned int i;
unsigned long x;
local_irq_save(x);
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
if (ptr == msgb_data[i]) {
if (!msgb_inuse[i]) {
TRACE_ERROR("%s: double_free by %s\r\n", __func__, location);
} else {
msgb_inuse[i] = 0;
}
local_irq_restore(x);
return 0;
}
}
local_irq_restore(x);
TRACE_ERROR("%s: invalid pointer %p from %s\r\n", __func__, ptr, location);
return -1;
}
void talloc_set_name_const(const void *ptr, const char *name)
{
/* do nothing */
}
#if 0
void *talloc_named_const(const void *context, size_t size, const char *name)
{
if (size)
TRACE_ERROR("%s: called with size!=0 from %s\r\n", __func__, name);
return NULL;
}
void *talloc_pool(const void *context, size_t size)
{
}
#endif

View File

@@ -1,140 +0,0 @@
/* USB Request Context for OpenPCD / OpenPICC / SIMtrace
* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include "chip.h"
#include "utils.h"
#include "trace.h"
#include "req_ctx.h"
#define NUM_RCTX_SMALL 10
#define NUM_RCTX_LARGE 0
#define NUM_REQ_CTX (NUM_RCTX_SMALL+NUM_RCTX_LARGE)
static uint8_t rctx_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL];
static uint8_t rctx_data_large[NUM_RCTX_LARGE][RCTX_SIZE_LARGE];
static struct req_ctx req_ctx[NUM_REQ_CTX];
struct req_ctx __ramfunc *
req_ctx_find_get(int large, uint32_t old_state, uint32_t new_state)
{
struct req_ctx *toReturn = NULL;
unsigned long flags;
unsigned int i;
if (old_state >= RCTX_STATE_COUNT || new_state >= RCTX_STATE_COUNT) {
TRACE_DEBUG("Invalid parameters for req_ctx_find_get\r\n");
return NULL;
}
local_irq_save(flags);
for (i = 0; i < ARRAY_SIZE(req_ctx); i++) {
if (req_ctx[i].state == old_state) {
toReturn = &req_ctx[i];
toReturn->state = new_state;
break;
}
}
local_irq_restore(flags);
TRACE_DEBUG("%s(%u, %u, %u)=%p\r\n", __func__, large, old_state,
new_state, toReturn);
return toReturn;
}
uint8_t req_ctx_num(struct req_ctx *ctx)
{
return ctx - req_ctx;
}
void req_ctx_set_state(struct req_ctx *ctx, uint32_t new_state)
{
unsigned long flags;
TRACE_DEBUG("%s(ctx=%p, new_state=%u)\r\n", __func__, ctx, new_state);
if (new_state >= RCTX_STATE_COUNT) {
TRACE_DEBUG("Invalid new_state for req_ctx_set_state\r\n");
return;
}
local_irq_save(flags);
ctx->state = new_state;
local_irq_restore(flags);
}
#ifdef DEBUG_REQCTX
void req_print(int state) {
int count = 0;
struct req_ctx *ctx, *last = NULL;
DEBUGP("State [%02i] start <==> ", state);
ctx = req_ctx_queues[state];
while (ctx) {
if (last != ctx->prev)
DEBUGP("*INV_PREV* ");
DEBUGP("%08X => ", ctx);
last = ctx;
ctx = ctx->next;
count++;
if (count > NUM_REQ_CTX) {
DEBUGP("*WILD POINTER* => ");
break;
}
}
TRACE_DEBUG("NULL");
if (!req_ctx_queues[state] && req_ctx_tails[state]) {
TRACE_DEBUG("NULL head, NON-NULL tail\r\n");
}
if (last != req_ctx_tails[state]) {
TRACE_DEBUG("Tail does not match last element\r\n");
}
}
#endif
void req_ctx_put(struct req_ctx *ctx)
{
return req_ctx_set_state(ctx, RCTX_S_FREE);
}
void req_ctx_init(void)
{
int i;
for (i = 0; i < NUM_RCTX_SMALL; i++) {
req_ctx[i].size = RCTX_SIZE_SMALL;
req_ctx[i].tot_len = 0;
req_ctx[i].data = rctx_data[i];
req_ctx[i].state = RCTX_S_FREE;
TRACE_DEBUG("SMALL req_ctx[%02i] initialized at %p, Data: %p => %p\r\n",
i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_SMALL);
}
for (; i < NUM_REQ_CTX; i++) {
req_ctx[i].size = RCTX_SIZE_LARGE;
req_ctx[i].tot_len = 0;
req_ctx[i].data = rctx_data_large[i];
req_ctx[i].state = RCTX_S_FREE;
TRACE_DEBUG("LARGE req_ctx[%02i] initialized at %p, Data: %p => %p\r\n",
i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_LARGE);
}
}

View File

@@ -1,7 +1,27 @@
/* Ring buffer
*
* 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 "ringbuffer.h" #include "ringbuffer.h"
#include "trace.h" #include "trace.h"
#include "utils.h" #include "utils.h"
/* WARNING: Since console output is internally using this ringbuffer to implement
* buffered writes, we cannot use any TRACE_*() or printf() style functions here,
* as it would create infinite recursion! */
void rbuf_reset(volatile ringbuf * rb) void rbuf_reset(volatile ringbuf * rb)
{ {
unsigned long state; unsigned long state;
@@ -52,7 +72,7 @@ bool rbuf_is_full(volatile ringbuf * rb)
return rc; return rc;
} }
void rbuf_write(volatile volatile ringbuf * rb, uint8_t item) int rbuf_write(volatile ringbuf * rb, uint8_t item)
{ {
unsigned long state; unsigned long state;
@@ -61,9 +81,10 @@ void rbuf_write(volatile volatile ringbuf * rb, uint8_t item)
rb->buf[rb->iwr] = item; rb->buf[rb->iwr] = item;
rb->iwr = (rb->iwr + 1) % RING_BUFLEN; rb->iwr = (rb->iwr + 1) % RING_BUFLEN;
local_irq_restore(state); local_irq_restore(state);
return 0;
} else { } else {
local_irq_restore(state); local_irq_restore(state);
TRACE_ERROR("Ringbuffer full, losing bytes!"); return -1;
} }
} }

View File

@@ -33,6 +33,7 @@
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "simtrace_usb.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "iso7816_fidi.h" #include "iso7816_fidi.h"
@@ -57,7 +58,7 @@ void ISR_PhoneRST(const Pin * pPin)
{ {
int ret; int ret;
// FIXME: no printfs in ISRs? // FIXME: no printfs in ISRs?
printf("+++ Int!! %x\n\r", pinPhoneRST.pio->PIO_ISR); printf("+++ Int!! %lx\n\r", pinPhoneRST.pio->PIO_ISR);
if (((pinPhoneRST.pio->PIO_ISR & pinPhoneRST.mask) != 0)) { if (((pinPhoneRST.pio->PIO_ISR & pinPhoneRST.mask) != 0)) {
if (PIO_Get(&pinPhoneRST) == 0) { if (PIO_Get(&pinPhoneRST) == 0) {
printf(" 0 "); printf(" 0 ");
@@ -67,7 +68,7 @@ void ISR_PhoneRST(const Pin * pPin)
} }
if ((ret = if ((ret =
USBD_Write(PHONE_INT, "R", 1, USBD_Write(SIMTRACE_USB_EP_PHONE_INT, "R", 1,
(TransferCallback) & Callback_PhoneRST_ISR, (TransferCallback) & Callback_PhoneRST_ISR,
0)) != USBD_STATUS_SUCCESS) { 0)) != USBD_STATUS_SUCCESS) {
TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__); TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__);
@@ -116,20 +117,27 @@ void mode_trace_usart1_irq(void)
} }
/* FIDI update functions */ /* FIDI update functions */
void update_fidi(uint8_t fidi) void update_fidi(Usart_info *usart, uint8_t fidi)
{ {
int rc; if (NULL==usart) {
return;
}
uint8_t fi = fidi >> 4; uint8_t fi = fidi >> 4;
uint8_t di = fidi & 0xf; uint8_t di = fidi & 0xf;
int ratio = compute_fidi_ratio(fi, di);
rc = compute_fidi_ratio(fi, di); if (ratio > 0 && ratio < 0x8000) {
if (rc > 0 && rc < 0x400) { /* make sure USART uses new F/D ratio */
TRACE_INFO("computed Fi(%u) Di(%u) ratio: %d", fi, di, rc); usart->base->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
/* make sure UART uses new F/D ratio */ /* disable write protection */
USART_PHONE->US_CR |= US_CR_RXDIS | US_CR_RSTRX; if (usart->base->US_WPMR) {
USART_PHONE->US_FIDI = rc & 0x3ff; usart->base->US_WPMR = US_WPMR_WPKEY(0x555341);
USART_PHONE->US_CR |= US_CR_RXEN | US_CR_STTTO; }
} else usart->base->US_FIDI = (ratio & 0x7ff);
TRACE_INFO("computed FiDi ratio %d unsupported", rc); usart->base->US_CR |= US_CR_RXEN | US_CR_STTTO;
//TRACE_INFO("updated USART(%u) Fi(%u)/Di(%u) ratio(%d): %u\n\r", usart->id, fi, di, ratio, usart->base->US_FIDI);
} else {
//TRACE_WARNING("computed Fi/Di ratio %d unsupported\n\r", ratio); /* don't print since this is function is also called by ISRs */
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation * Copyright (c) 2008, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -61,8 +62,10 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// //
FILE* const stdin = NULL; FILE* const stdin = NULL;
FILE* const stdout = NULL; /* If we use NULL here, we get compiler warnings of calling stdio functions with
FILE* const stderr = NULL; * NULL values. Our fputs() implementation ignores the value of those pointers anyway */
FILE* const stdout = (FILE *) 0x1;
FILE* const stderr = (FILE *) 0x2;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -435,6 +438,32 @@ signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
return fputs(pStr, pStream); return fputs(pStr, pStream);
} }
//------------------------------------------------------------------------------
/// Outputs a formatted string on the given stream. Format arguments are given
/// in a va_list instance.
/// \note This function is synchronous (i.e. blocks until the print completes)
/// \param pStream Output stream.
/// \param pFormat Format string
/// \param ap Argument list.
//------------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
signed int vfprintf_sync(FILE *pStream, const char *pFormat, va_list ap)
{
char pStr[MAX_STRING_SIZE];
char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
// Write formatted string in buffer
if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
fputs_sync(pError, stderr);
}
// Display string
return fputs_sync(pStr, pStream);
}
#pragma GCC diagnostic pop
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Outputs a formatted string on the DBGU stream. Format arguments are given /// Outputs a formatted string on the DBGU stream. Format arguments are given
/// in a va_list instance. /// in a va_list instance.
@@ -446,6 +475,18 @@ signed int vprintf(const char *pFormat, va_list ap)
return vfprintf(stdout, pFormat, ap); return vfprintf(stdout, pFormat, ap);
} }
//------------------------------------------------------------------------------
/// Outputs a formatted string on the DBGU stream. Format arguments are given
/// in a va_list instance.
/// \note This function is synchronous (i.e. blocks until the print completes)
/// \param pFormat Format string
/// \param ap Argument list.
//------------------------------------------------------------------------------
signed int vprintf_sync(const char *pFormat, va_list ap)
{
return vfprintf_sync(stdout, pFormat, ap);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Outputs a formatted string on the given stream, using a variable number of /// Outputs a formatted string on the given stream, using a variable number of
/// arguments. /// arguments.
@@ -483,6 +524,25 @@ signed int printf(const char *pFormat, ...)
return result; return result;
} }
//------------------------------------------------------------------------------
/// Outputs a formatted string on the DBGU stream, using a variable number of
/// arguments.
/// \note This function is synchronous (i.e. blocks until the print completes)
/// \param pFormat Format string.
//------------------------------------------------------------------------------
signed int printf_sync(const char *pFormat, ...)
{
va_list ap;
signed int result;
// Forward call to vprintf
va_start(ap, pFormat);
result = vprintf_sync(pFormat, ap);
va_end(ap);
return result;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Writes a formatted string inside another string. /// Writes a formatted string inside another string.
/// \param pStr Storage string. /// \param pStr Storage string.

View File

@@ -1,6 +1,6 @@
/* SIMtrace TC (Timer / Clock) code for ETU tracking */ /* SIMtrace TC (Timer / Clock) code for ETU tracking
*
/* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2006-2016 by Harald Welte <laforge@gnumonks.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,10 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
*/ */
#include <stdint.h> #include <stdint.h>
#include "utils.h" #include "utils.h"
@@ -25,17 +23,17 @@
#include "chip.h" #include "chip.h"
/* pins for Channel 0 of TC-block 0 */ /* pins for Channel 0 of TC-block 0, we only use TCLK + TIOB */
#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT } #define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_TIOB0 {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_TIOB0 {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOA0, PIN_TIOB0 }; static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOB0 };
/* pins for Channel 2 of TC-block 0 */ /* pins for Channel 2 of TC-block 0, we only use TCLK + TIOB */
#define PIN_TCLK2 {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_TCLK2 {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_TIOA2 {PIO_PA26, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_TIOA2 {PIO_PA26, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_TIOB2 {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_TIOB2 {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOA2, PIN_TIOB2 }; static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOB2 };
struct tc_etu_state { struct tc_etu_state {
/* total negotiated waiting time (default = 9600) */ /* total negotiated waiting time (default = 9600) */
@@ -158,7 +156,7 @@ void tc_etu_init(uint8_t chan_nr, void *handle)
switch (chan_nr) { switch (chan_nr) {
case 0: case 0:
/* Configure PA4(TCLK0), PA0(TIOA0), PA1(TIB0) */ /* Configure PA4(TCLK0), PA1(TIB0) */
PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0)); PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0));
PMC_EnablePeripheral(ID_TC0); PMC_EnablePeripheral(ID_TC0);
/* route TCLK0 to XC2 */ /* route TCLK0 to XC2 */
@@ -171,7 +169,7 @@ void tc_etu_init(uint8_t chan_nr, void *handle)
te->chan = &TC0->TC_CHANNEL[0]; te->chan = &TC0->TC_CHANNEL[0];
break; break;
case 2: case 2:
/* Configure PA29(TCLK2), PA26(TIOA2), PA27(TIOB2) */ /* Configure PA29(TCLK2), PA27(TIOB2) */
PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2)); PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2));
PMC_EnablePeripheral(ID_TC2); PMC_EnablePeripheral(ID_TC2);
/* route TCLK2 to XC2. TC0 really means TCA in this case */ /* route TCLK2 to XC2. TC0 really means TCA in this case */

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -33,7 +34,9 @@
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "simtrace_usb.h"
#include "utils.h" #include "utils.h"
#include "USBD_HAL.h"
#include <cciddriverdescriptors.h> #include <cciddriverdescriptors.h>
#include <usb/common/dfu/usb_dfu.h> #include <usb/common/dfu/usb_dfu.h>
@@ -42,191 +45,10 @@
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* USB String descriptors * USB String descriptors
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
#include "usb_strings_generated.h"
static const unsigned char langDesc[] = {
USBStringDescriptor_LENGTH(1),
USBGenericDescriptor_STRING,
USBStringDescriptor_ENGLISH_US
};
const unsigned char manufStringDescriptor[] = {
USBStringDescriptor_LENGTH(24),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('y'),
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('-'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('s'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE('f'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('.'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('G'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('b'),
USBStringDescriptor_UNICODE('H'),
};
const unsigned char productStringDescriptor[] = {
USBStringDescriptor_LENGTH(10),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('2'),
};
const unsigned char snifferConfigStringDescriptor[] = {
USBStringDescriptor_LENGTH(16),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('n'),
USBStringDescriptor_UNICODE('i'),
USBStringDescriptor_UNICODE('f'),
USBStringDescriptor_UNICODE('f'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE('r'),
};
const unsigned char CCIDConfigStringDescriptor[] = {
USBStringDescriptor_LENGTH(13),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('C'),
USBStringDescriptor_UNICODE('C'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('D'),
};
const unsigned char phoneConfigStringDescriptor[] = {
USBStringDescriptor_LENGTH(14),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('P'),
USBStringDescriptor_UNICODE('h'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('n'),
USBStringDescriptor_UNICODE('e'),
};
const unsigned char MITMConfigStringDescriptor[] = {
USBStringDescriptor_LENGTH(13),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('c'),
USBStringDescriptor_UNICODE('e'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('T'),
USBStringDescriptor_UNICODE('M'),
};
const unsigned char cardem_usim1_intf_str[] = {
USBStringDescriptor_LENGTH(18),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('C'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('d'),
USBStringDescriptor_UNICODE('E'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('u'),
USBStringDescriptor_UNICODE('l'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('U'),
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('1'),
};
const unsigned char cardem_usim2_intf_str[] = {
USBStringDescriptor_LENGTH(18),
USBGenericDescriptor_STRING,
USBStringDescriptor_UNICODE('C'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE('d'),
USBStringDescriptor_UNICODE('E'),
USBStringDescriptor_UNICODE('m'),
USBStringDescriptor_UNICODE('u'),
USBStringDescriptor_UNICODE('l'),
USBStringDescriptor_UNICODE('a'),
USBStringDescriptor_UNICODE('t'),
USBStringDescriptor_UNICODE('o'),
USBStringDescriptor_UNICODE('r'),
USBStringDescriptor_UNICODE(' '),
USBStringDescriptor_UNICODE('U'),
USBStringDescriptor_UNICODE('S'),
USBStringDescriptor_UNICODE('I'),
USBStringDescriptor_UNICODE('M'),
USBStringDescriptor_UNICODE('2'),
};
enum strDescNum { enum strDescNum {
PRODUCT_STRING = 1, MANUF_STR = 1,
MANUF_STR, PRODUCT_STRING,
SNIFFER_CONF_STR, SNIFFER_CONF_STR,
CCID_CONF_STR, CCID_CONF_STR,
PHONE_CONF_STR, PHONE_CONF_STR,
@@ -236,19 +58,6 @@ enum strDescNum {
STRING_DESC_CNT STRING_DESC_CNT
}; };
/** List of string descriptors used by the device */
static const unsigned char *stringDescriptors[] = {
langDesc,
[PRODUCT_STRING] = productStringDescriptor,
[MANUF_STR] = manufStringDescriptor,
[SNIFFER_CONF_STR] = snifferConfigStringDescriptor,
[CCID_CONF_STR] = CCIDConfigStringDescriptor,
[PHONE_CONF_STR] = phoneConfigStringDescriptor,
[MITM_CONF_STR] = MITMConfigStringDescriptor,
[CARDEM_USIM1_INTF_STR] = cardem_usim1_intf_str,
[CARDEM_USIM2_INTF_STR] = cardem_usim2_intf_str,
};
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* USB Device descriptors * USB Device descriptors
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
@@ -268,7 +77,7 @@ typedef struct _SIMTraceDriverConfigurationDescriptorSniffer {
static const SIMTraceDriverConfigurationDescriptorSniffer static const SIMTraceDriverConfigurationDescriptorSniffer
configurationDescriptorSniffer = { configurationDescriptorSniffer = {
/* Standard configuration descriptor */ /* Standard configuration descriptor */
{ .configuration = {
.bLength = sizeof(USBConfigurationDescriptor), .bLength = sizeof(USBConfigurationDescriptor),
.bDescriptorType = USBGenericDescriptor_CONFIGURATION, .bDescriptorType = USBGenericDescriptor_CONFIGURATION,
.wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorSniffer), .wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorSniffer),
@@ -279,54 +88,48 @@ static const SIMTraceDriverConfigurationDescriptorSniffer
.bMaxPower = USBConfigurationDescriptor_POWER(100), .bMaxPower = USBConfigurationDescriptor_POWER(100),
}, },
/* Communication class interface standard descriptor */ /* Communication class interface standard descriptor */
{ .sniffer = {
.bLength = sizeof(USBInterfaceDescriptor), .bLength = sizeof(USBInterfaceDescriptor),
.bDescriptorType = USBGenericDescriptor_INTERFACE, .bDescriptorType = USBGenericDescriptor_INTERFACE,
.bInterfaceNumber = 0, .bInterfaceNumber = 0,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 3, .bNumEndpoints = 3,
.bInterfaceClass = 0xff, .bInterfaceClass = USB_CLASS_PROPRIETARY,
.bInterfaceSubClass = 0, .bInterfaceSubClass = SIMTRACE_SNIFFER_USB_SUBCLASS,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = SNIFFER_CONF_STR, .iInterface = SNIFFER_CONF_STR,
}, },
/* Bulk-OUT endpoint standard descriptor */ /* Bulk-OUT endpoint standard descriptor */
{ .sniffer_dataOut = {
.bLength = sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
.bDescriptorType = USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
.bEndpointAddress = USBEndpointDescriptor_ADDRESS( .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
USBEndpointDescriptor_OUT, USBEndpointDescriptor_OUT,
PHONE_DATAOUT), SIMTRACE_USB_EP_CARD_DATAOUT),
.bmAttributes = USBEndpointDescriptor_BULK, .bmAttributes = USBEndpointDescriptor_BULK,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
PHONE_DATAOUT),
USBEndpointDescriptor_MAXBULKSIZE_FS),
.bInterval = 0, .bInterval = 0,
}, },
/* Bulk-IN endpoint descriptor */ /* Bulk-IN endpoint descriptor */
{ .sniffer_dataIn = {
.bLength = sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
.bDescriptorType = USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
.bEndpointAddress = USBEndpointDescriptor_ADDRESS( .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
USBEndpointDescriptor_IN, USBEndpointDescriptor_IN,
PHONE_DATAIN), SIMTRACE_USB_EP_CARD_DATAIN),
.bmAttributes = USBEndpointDescriptor_BULK, .bmAttributes = USBEndpointDescriptor_BULK,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
PHONE_DATAIN),
USBEndpointDescriptor_MAXBULKSIZE_FS),
.bInterval = 0, .bInterval = 0,
}, },
// Notification endpoint descriptor // Notification endpoint descriptor
{ .sniffer_interruptIn = {
.bLength = sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
.bDescriptorType = USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
.bEndpointAddress = USBEndpointDescriptor_ADDRESS( .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
USBEndpointDescriptor_IN, USBEndpointDescriptor_IN,
PHONE_INT), SIMTRACE_USB_EP_CARD_INT),
.bmAttributes = USBEndpointDescriptor_INTERRUPT, .bmAttributes = USBEndpointDescriptor_INTERRUPT,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS,
PHONE_INT),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
.bInterval = 0x10, .bInterval = 0x10,
}, },
DFURT_IF_DESCRIPTOR(1, 0), DFURT_IF_DESCRIPTOR(1, 0),
@@ -396,9 +199,7 @@ static const CCIDDriverConfigurationDescriptors configurationDescriptorCCID = {
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
CCID_EPT_DATA_OUT), CCID_EPT_DATA_OUT),
.bmAttributes = USBEndpointDescriptor_BULK, .bmAttributes = USBEndpointDescriptor_BULK,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
CCID_EPT_DATA_OUT),
USBEndpointDescriptor_MAXBULKSIZE_FS),
.bInterval = 0x00, .bInterval = 0x00,
}, },
// Bulk-IN endpoint descriptor // Bulk-IN endpoint descriptor
@@ -409,9 +210,7 @@ static const CCIDDriverConfigurationDescriptors configurationDescriptorCCID = {
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
CCID_EPT_DATA_IN), CCID_EPT_DATA_IN),
.bmAttributes = USBEndpointDescriptor_BULK, .bmAttributes = USBEndpointDescriptor_BULK,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS),
CCID_EPT_DATA_IN),
USBEndpointDescriptor_MAXBULKSIZE_FS),
.bInterval = 0x00, .bInterval = 0x00,
}, },
// Notification endpoint descriptor // Notification endpoint descriptor
@@ -422,9 +221,7 @@ static const CCIDDriverConfigurationDescriptors configurationDescriptorCCID = {
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
CCID_EPT_NOTIFICATION), CCID_EPT_NOTIFICATION),
.bmAttributes = USBEndpointDescriptor_INTERRUPT, .bmAttributes = USBEndpointDescriptor_INTERRUPT,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS,
CCID_EPT_NOTIFICATION),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
.bInterval = 0x10, .bInterval = 0x10,
}, },
DFURT_IF_DESCRIPTOR(1, 0), DFURT_IF_DESCRIPTOR(1, 0),
@@ -452,111 +249,111 @@ typedef struct _SIMTraceDriverConfigurationDescriptorPhone {
static const SIMTraceDriverConfigurationDescriptorPhone static const SIMTraceDriverConfigurationDescriptorPhone
configurationDescriptorPhone = { configurationDescriptorPhone = {
/* Standard configuration descriptor */ /* Standard configuration descriptor */
{ .configuration = {
sizeof(USBConfigurationDescriptor), .bLength = sizeof(USBConfigurationDescriptor),
USBGenericDescriptor_CONFIGURATION, .bDescriptorType = USBGenericDescriptor_CONFIGURATION,
sizeof(SIMTraceDriverConfigurationDescriptorPhone), .wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorPhone),
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
2+DFURT_NUM_IF, .bNumInterfaces = 2+DFURT_NUM_IF,
#else #else
1+DFURT_NUM_IF, /* There is one interface in this configuration */ .bNumInterfaces = 1+DFURT_NUM_IF,
#endif #endif
CFG_NUM_PHONE, /* configuration number */ .bConfigurationValue = CFG_NUM_PHONE,
PHONE_CONF_STR, /* string descriptor for this configuration */ .iConfiguration = PHONE_CONF_STR,
USBD_BMATTRIBUTES, .bmAttributes = USBD_BMATTRIBUTES,
USBConfigurationDescriptor_POWER(100) .bMaxPower = USBConfigurationDescriptor_POWER(100)
}, },
/* Communication class interface standard descriptor */ /* Communication class interface standard descriptor */
{ .phone = {
sizeof(USBInterfaceDescriptor), .bLength = sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE, .bDescriptorType = USBGenericDescriptor_INTERFACE,
0, /* This is interface #0 */ .bInterfaceNumber = 0,
0, /* This is alternate setting #0 for this interface */ .bAlternateSetting = 0,
3, /* Number of endpoints */ .bNumEndpoints = 3,
0xff, /* Descriptor Class: Vendor specific */ .bInterfaceClass = USB_CLASS_PROPRIETARY,
0, /* No subclass */ .bInterfaceSubClass = SIMTRACE_CARDEM_USB_SUBCLASS,
0, /* No l */ .bInterfaceProtocol = 0,
CARDEM_USIM1_INTF_STR .iInterface = CARDEM_USIM1_INTF_STR,
}, },
/* Bulk-OUT endpoint standard descriptor */ /* Bulk-OUT endpoint standard descriptor */
{ .phone_dataOut = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
PHONE_DATAOUT), USBEndpointDescriptor_OUT,
USBEndpointDescriptor_BULK, SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAOUT), .bmAttributes = USBEndpointDescriptor_BULK,
USBEndpointDescriptor_MAXBULKSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
0 /* Must be 0 for full-speed bulk endpoints */ .bInterval = 0 /* Must be 0 for full-speed bulk endpoints */
}, },
/* Bulk-IN endpoint descriptor */ /* Bulk-IN endpoint descriptor */
{ .phone_dataIn = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
PHONE_DATAIN), USBEndpointDescriptor_IN,
USBEndpointDescriptor_BULK, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAIN), .bmAttributes = USBEndpointDescriptor_BULK,
USBEndpointDescriptor_MAXBULKSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
0 /* Must be 0 for full-speed bulk endpoints */ .bInterval = 0 /* Must be 0 for full-speed bulk endpoints */
}, },
/* Notification endpoint descriptor */ /* Notification endpoint descriptor */
{ .phone_interruptIn = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
PHONE_INT), USBEndpointDescriptor_IN,
USBEndpointDescriptor_INTERRUPT, SIMTRACE_CARDEM_USB_EP_USIM1_INT),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_INT), .bmAttributes = USBEndpointDescriptor_INTERRUPT,
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS,
0x10 .bInterval = 0x10
}, },
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
/* Communication class interface standard descriptor */ /* Communication class interface standard descriptor */
{ .usim2 = {
sizeof(USBInterfaceDescriptor), .bLength = sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE, .bDescriptorType = USBGenericDescriptor_INTERFACE,
1, /* This is interface #1 */ .bInterfaceNumber = 1,
0, /* This is alternate setting #0 for this interface */ .bAlternateSetting = 0,
3, /* Number of endpoints */ .bNumEndpoints = 3,
0xff, /* Descriptor Class: Vendor specific */ .bInterfaceClass = USB_CLASS_PROPRIETARY,
0, /* No subclass */ .bInterfaceSubClass = SIMTRACE_CARDEM_USB_SUBCLASS,
0, /* No l */ .bInterfaceProtocol = 0,
CARDEM_USIM2_INTF_STR .iInterface = CARDEM_USIM2_INTF_STR,
}, },
/* Bulk-OUT endpoint standard descriptor */ /* Bulk-OUT endpoint standard descriptor */
{ .usim2_dataOut = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
CARDEM_USIM2_DATAOUT), USBEndpointDescriptor_OUT,
USBEndpointDescriptor_BULK, SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CARDEM_USIM2_DATAOUT), .bmAttributes = USBEndpointDescriptor_BULK,
USBEndpointDescriptor_MAXBULKSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
0 /* Must be 0 for full-speed bulk endpoints */ .bInterval = 0 /* Must be 0 for full-speed bulk endpoints */
} }
, ,
/* Bulk-IN endpoint descriptor */ /* Bulk-IN endpoint descriptor */
{ .usim2_dataIn = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
CARDEM_USIM2_DATAIN), USBEndpointDescriptor_IN,
USBEndpointDescriptor_BULK, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CARDEM_USIM2_DATAIN), .bmAttributes = USBEndpointDescriptor_BULK,
USBEndpointDescriptor_MAXBULKSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
0 /* Must be 0 for full-speed bulk endpoints */ .bInterval = 0 /* Must be 0 for full-speed bulk endpoints */
}, },
/* Notification endpoint descriptor */ /* Notification endpoint descriptor */
{ .usim2_interruptIn = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
CARDEM_USIM2_INT), USBEndpointDescriptor_IN,
USBEndpointDescriptor_INTERRUPT, SIMTRACE_CARDEM_USB_EP_USIM2_INT),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CARDEM_USIM2_INT), .bmAttributes = USBEndpointDescriptor_INTERRUPT,
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS,
0x10 .bInterval = 0x10,
}, },
DFURT_IF_DESCRIPTOR(2, 0), DFURT_IF_DESCRIPTOR(2, 0),
#else #else
@@ -591,20 +388,20 @@ typedef struct _SIMTraceDriverConfigurationDescriptorMITM {
static const SIMTraceDriverConfigurationDescriptorMITM static const SIMTraceDriverConfigurationDescriptorMITM
configurationDescriptorMITM = { configurationDescriptorMITM = {
/* Standard configuration descriptor */ /* Standard configuration descriptor */
{ .configuration = {
sizeof(USBConfigurationDescriptor), .bLength = sizeof(USBConfigurationDescriptor),
USBGenericDescriptor_CONFIGURATION, .bDescriptorType = USBGenericDescriptor_CONFIGURATION,
sizeof(SIMTraceDriverConfigurationDescriptorMITM), .wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorMITM),
2+DFURT_NUM_IF, /* There are two interfaces in this configuration */ .bNumInterfaces = 2+DFURT_NUM_IF,
CFG_NUM_MITM, /* configuration number */ .bConfigurationValue = CFG_NUM_MITM,
MITM_CONF_STR, /* string descriptor for this configuration */ .iConfiguration = MITM_CONF_STR,
USBD_BMATTRIBUTES, .bmAttributes = USBD_BMATTRIBUTES,
USBConfigurationDescriptor_POWER(100) .bMaxPower = USBConfigurationDescriptor_POWER(100),
}, },
// CCID interface descriptor // CCID interface descriptor
// Table 4.3-1 Interface Descriptor // Table 4.3-1 Interface Descriptor
// Interface descriptor // Interface descriptor
{ .simcard = {
.bLength = sizeof(USBInterfaceDescriptor), .bLength = sizeof(USBInterfaceDescriptor),
.bDescriptorType = USBGenericDescriptor_INTERFACE, .bDescriptorType = USBGenericDescriptor_INTERFACE,
.bInterfaceNumber = 0, .bInterfaceNumber = 0,
@@ -615,7 +412,7 @@ static const SIMTraceDriverConfigurationDescriptorMITM
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = CCID_CONF_STR, .iInterface = CCID_CONF_STR,
}, },
{ .ccid = {
.bLength = sizeof(CCIDDescriptor), .bLength = sizeof(CCIDDescriptor),
.bDescriptorType = CCID_DECRIPTOR_TYPE, .bDescriptorType = CCID_DECRIPTOR_TYPE,
.bcdCCID = CCID1_10, // CCID version .bcdCCID = CCID1_10, // CCID version
@@ -644,91 +441,84 @@ static const SIMTraceDriverConfigurationDescriptorMITM
.bMaxCCIDBusySlots = 1, .bMaxCCIDBusySlots = 1,
}, },
// Bulk-OUT endpoint descriptor // Bulk-OUT endpoint descriptor
{ .simcard_dataOut = {
.bLength = sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
.bDescriptorType = USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
.bEndpointAddress = .bEndpointAddress =
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
CCID_EPT_DATA_OUT), CCID_EPT_DATA_OUT),
.bmAttributes = USBEndpointDescriptor_BULK, .bmAttributes = USBEndpointDescriptor_BULK,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
CCID_EPT_DATA_OUT),
USBEndpointDescriptor_MAXBULKSIZE_FS),
.bInterval = 0x00, .bInterval = 0x00,
}, },
// Bulk-IN endpoint descriptor // Bulk-IN endpoint descriptor
{ .simcard_dataIn = {
.bLength = sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
.bDescriptorType = USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
.bEndpointAddress = .bEndpointAddress =
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
CCID_EPT_DATA_IN), CCID_EPT_DATA_IN),
.bmAttributes = USBEndpointDescriptor_BULK, .bmAttributes = USBEndpointDescriptor_BULK,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
CCID_EPT_DATA_IN),
USBEndpointDescriptor_MAXBULKSIZE_FS),
.bInterval = 0x00, .bInterval = 0x00,
}, },
// Notification endpoint descriptor // Notification endpoint descriptor
{ .simcard_interruptIn = {
.bLength = sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
.bDescriptorType = USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
.bEndpointAddress = .bEndpointAddress =
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
CCID_EPT_NOTIFICATION), CCID_EPT_NOTIFICATION),
.bmAttributes = USBEndpointDescriptor_INTERRUPT, .bmAttributes = USBEndpointDescriptor_INTERRUPT,
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS,
CCID_EPT_NOTIFICATION),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
.bInterval = 0x10, .bInterval = 0x10,
}, },
/* Communication class interface standard descriptor */ /* Communication class interface standard descriptor */
{ .phone = {
sizeof(USBInterfaceDescriptor), .bLength = sizeof(USBInterfaceDescriptor),
USBGenericDescriptor_INTERFACE, .bDescriptorType = USBGenericDescriptor_INTERFACE,
1, /* This is interface #1 */ .bInterfaceNumber = 1,
0, /* This is alternate setting #0 for this interface */ .bAlternateSetting = 0,
3, /* Number of endpoints */ .bNumEndpoints = 3,
0xff, .bInterfaceClass = 0xff,
0, .bInterfaceSubClass = SIMTRACE_SUBCLASS_CARDEM,
0, .bInterfaceProtocol = 0,
PHONE_CONF_STR, /* string descriptor for this interface */ .iInterface = PHONE_CONF_STR,
} },
,
/* Bulk-OUT endpoint standard descriptor */ /* Bulk-OUT endpoint standard descriptor */
{ .phone_dataOut = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
PHONE_DATAOUT), USBEndpointDescriptor_OUT,
USBEndpointDescriptor_BULK, SIMTRACE_USB_EP_PHONE_DATAOUT),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAOUT), .bmAttributes = USBEndpointDescriptor_BULK,
USBEndpointDescriptor_MAXBULKSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
0 /* Must be 0 for full-speed bulk endpoints */ .bInterval = 0, /* Must be 0 for full-speed bulk endpoints */
} },
,
/* Bulk-IN endpoint descriptor */ /* Bulk-IN endpoint descriptor */
{ .phone_dataIn = {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
PHONE_DATAIN), USBEndpointDescriptor_IN,
USBEndpointDescriptor_BULK, SIMTRACE_USB_EP_PHONE_DATAIN),
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAIN), .bmAttributes = USBEndpointDescriptor_BULK,
USBEndpointDescriptor_MAXBULKSIZE_FS), .wMaxPacketSize = USBEndpointDescriptor_MAXBULKSIZE_FS,
0 /* Must be 0 for full-speed bulk endpoints */ .bInterval = 0, /* Must be 0 for full-speed bulk endpoints */
} },
,
/* Notification endpoint descriptor */ /* Notification endpoint descriptor */
{ {
sizeof(USBEndpointDescriptor), .bLength = sizeof(USBEndpointDescriptor),
USBGenericDescriptor_ENDPOINT, .bDescriptorType = USBGenericDescriptor_ENDPOINT,
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, PHONE_INT), .bEndpointAddress = USBEndpointDescriptor_ADDRESS(
USBEndpointDescriptor_INTERRUPT, USBEndpointDescriptor_IN,
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_INT), SIMTRACE_USB_EP_PHONE_INT),
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), .bmAttributes = USBEndpointDescriptor_INTERRUPT,
0x10}, .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS,
.bInterval = 0x10
},
DFURT_IF_DESCRIPTOR(2, 0), DFURT_IF_DESCRIPTOR(2, 0),
}; };
#endif /* HAVE_CARDEM */ #endif /* HAVE_CARDEM */
@@ -753,12 +543,12 @@ const USBDeviceDescriptor deviceDescriptor = {
.bLength = sizeof(USBDeviceDescriptor), .bLength = sizeof(USBDeviceDescriptor),
.bDescriptorType = USBGenericDescriptor_DEVICE, .bDescriptorType = USBGenericDescriptor_DEVICE,
.bcdUSB = USBDeviceDescriptor_USB2_00, .bcdUSB = USBDeviceDescriptor_USB2_00,
.bDeviceClass = 0xff, .bDeviceClass = 0,
.bDeviceSubClass = 0xff, .bDeviceSubClass = 0,
.bDeviceProtocol = 0xff, .bDeviceProtocol = 0,
.bMaxPacketSize0 = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), .bMaxPacketSize0 = 64,
.idVendor = SIMTRACE_VENDOR_ID, .idVendor = BOARD_USB_VENDOR_ID,
.idProduct = SIMTRACE_PRODUCT_ID, .idProduct = BOARD_USB_PRODUCT_ID,
.bcdDevice = 2, /* Release number */ .bcdDevice = 2, /* Release number */
.iManufacturer = MANUF_STR, .iManufacturer = MANUF_STR,
.iProduct = PRODUCT_STRING, .iProduct = PRODUCT_STRING,
@@ -776,8 +566,8 @@ static const USBDDriverDescriptors driverDescriptors = {
0, /* No high-speed configuration descriptor */ 0, /* No high-speed configuration descriptor */
0, /* No high-speed device qualifier descriptor */ 0, /* No high-speed device qualifier descriptor */
0, /* No high-speed other speed configuration descriptor */ 0, /* No high-speed other speed configuration descriptor */
stringDescriptors, usb_strings,
STRING_DESC_CNT /* cnt string descriptors in list */ ARRAY_SIZE(usb_strings),/* cnt string descriptors in list */
}; };
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@@ -786,11 +576,23 @@ static const USBDDriverDescriptors driverDescriptors = {
void SIMtrace_USB_Initialize(void) void SIMtrace_USB_Initialize(void)
{ {
/* Signal USB reset by disabling the pull-up on USB D+ for at least 10 ms */
#ifdef PIN_USB_PULLUP
const Pin usb_dp_pullup = PIN_USB_PULLUP;
PIO_Configure(&usb_dp_pullup, 1);
PIO_Set(&usb_dp_pullup);
#endif
USBD_HAL_Suspend();
mdelay(20);
#ifdef PIN_USB_PULLUP
PIO_Clear(&usb_dp_pullup);
#endif
USBD_HAL_Activate();
// Get std USB driver // Get std USB driver
USBDDriver *pUsbd = USBD_GetDriver(); USBDDriver *pUsbd = USBD_GetDriver();
TRACE_DEBUG(".");
// Initialize standard USB driver // Initialize standard USB driver
USBDDriver_Initialize(pUsbd, &driverDescriptors, 0); // Multiple interface settings not supported USBDDriver_Initialize(pUsbd, &driverDescriptors, 0); // Multiple interface settings not supported
USBD_Init(); USBD_Init();

View File

@@ -0,0 +1,93 @@
/* USB buffer library
*
* 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 "usb_buf.h"
#include "simtrace_usb.h"
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <errno.h>
#define USB_ALLOC_SIZE 280
static struct usb_buffered_ep usb_buffered_ep[BOARD_USB_NUMENDPOINTS];
struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep)
{
if (ep >= ARRAY_SIZE(usb_buffered_ep))
return NULL;
return &usb_buffered_ep[ep];
}
/***********************************************************************
* User API
***********************************************************************/
struct llist_head *usb_get_queue(uint8_t ep)
{
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
if (!bep)
return NULL;
return &bep->queue;
}
/* allocate a USB buffer for use with given end-point */
struct msgb *usb_buf_alloc(uint8_t ep)
{
struct msgb *msg;
msg = msgb_alloc(USB_ALLOC_SIZE, "USB");
if (!msg)
return NULL;
msg->dst = usb_get_buf_ep(ep);
return msg;
}
/* release/return the USB buffer to the pool */
void usb_buf_free(struct msgb *msg)
{
msgb_free(msg);
}
/* submit a USB buffer for transmission to host */
int usb_buf_submit(struct msgb *msg)
{
struct usb_buffered_ep *ep = msg->dst;
if (!msg->dst) {
TRACE_ERROR("%s: msg without dst\r\n", __func__);
usb_buf_free(msg);
return -EINVAL;
}
/* no need for irqsafe operation, as the usb_tx_queue is
* processed only by the main loop context */
msgb_enqueue(&ep->queue, msg);
return 0;
}
void usb_buf_init(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(usb_buffered_ep); i++) {
struct usb_buffered_ep *ep = &usb_buffered_ep[i];
INIT_LLIST_HEAD(&ep->queue);
}
}

View File

@@ -0,0 +1,4 @@
#pragma once
void osmo_generate_backtrace(void);
void osmo_log_backtrace(int subsys, int level);

View File

@@ -0,0 +1,105 @@
/*
* bit16gen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint16_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 16 bit unsigned integer
*/
static inline uint16_t osmo_load16le_ext(const void *p, uint8_t n)
{
uint8_t i;
uint16_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint16_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint16_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 16 bit unsigned integer
*/
static inline uint16_t osmo_load16be_ext(const void *p, uint8_t n)
{
uint8_t i;
uint16_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint16_t)q[i] << (16 - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint16_t
* \param[in] x unsigned 16 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store16le_ext(uint16_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint16_t
* \param[in] x unsigned 16 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store16be_ext(uint16_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned 16-bit integer (little-endian encoding) */
static inline uint16_t osmo_load16le(const void *p)
{
return osmo_load16le_ext(p, 16 / 8);
}
/*! \brief load unaligned 16-bit integer (big-endian encoding) */
static inline uint16_t osmo_load16be(const void *p)
{
return osmo_load16be_ext(p, 16 / 8);
}
/*! \brief store unaligned 16-bit integer (little-endian encoding) */
static inline void osmo_store16le(uint16_t x, void *p)
{
osmo_store16le_ext(x, p, 16 / 8);
}
/*! \brief store unaligned 16-bit integer (big-endian encoding) */
static inline void osmo_store16be(uint16_t x, void *p)
{
osmo_store16be_ext(x, p, 16 / 8);
}

View File

@@ -0,0 +1,105 @@
/*
* bit32gen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint32_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 32 bit unsigned integer
*/
static inline uint32_t osmo_load32le_ext(const void *p, uint8_t n)
{
uint8_t i;
uint32_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint32_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint32_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 32 bit unsigned integer
*/
static inline uint32_t osmo_load32be_ext(const void *p, uint8_t n)
{
uint8_t i;
uint32_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint32_t)q[i] << (32 - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint32_t
* \param[in] x unsigned 32 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store32le_ext(uint32_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint32_t
* \param[in] x unsigned 32 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store32be_ext(uint32_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned 32-bit integer (little-endian encoding) */
static inline uint32_t osmo_load32le(const void *p)
{
return osmo_load32le_ext(p, 32 / 8);
}
/*! \brief load unaligned 32-bit integer (big-endian encoding) */
static inline uint32_t osmo_load32be(const void *p)
{
return osmo_load32be_ext(p, 32 / 8);
}
/*! \brief store unaligned 32-bit integer (little-endian encoding) */
static inline void osmo_store32le(uint32_t x, void *p)
{
osmo_store32le_ext(x, p, 32 / 8);
}
/*! \brief store unaligned 32-bit integer (big-endian encoding) */
static inline void osmo_store32be(uint32_t x, void *p)
{
osmo_store32be_ext(x, p, 32 / 8);
}

View File

@@ -0,0 +1,105 @@
/*
* bit64gen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint64_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 64 bit unsigned integer
*/
static inline uint64_t osmo_load64le_ext(const void *p, uint8_t n)
{
uint8_t i;
uint64_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint64_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint64_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 64 bit unsigned integer
*/
static inline uint64_t osmo_load64be_ext(const void *p, uint8_t n)
{
uint8_t i;
uint64_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint64_t)q[i] << (64 - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint64_t
* \param[in] x unsigned 64 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store64le_ext(uint64_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint64_t
* \param[in] x unsigned 64 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store64be_ext(uint64_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned 64-bit integer (little-endian encoding) */
static inline uint64_t osmo_load64le(const void *p)
{
return osmo_load64le_ext(p, 64 / 8);
}
/*! \brief load unaligned 64-bit integer (big-endian encoding) */
static inline uint64_t osmo_load64be(const void *p)
{
return osmo_load64be_ext(p, 64 / 8);
}
/*! \brief store unaligned 64-bit integer (little-endian encoding) */
static inline void osmo_store64le(uint64_t x, void *p)
{
osmo_store64le_ext(x, p, 64 / 8);
}
/*! \brief store unaligned 64-bit integer (big-endian encoding) */
static inline void osmo_store64be(uint64_t x, void *p)
{
osmo_store64be_ext(x, p, 64 / 8);
}

View File

@@ -0,0 +1,118 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <osmocom/core/bit16gen.h>
#include <osmocom/core/bit32gen.h>
#include <osmocom/core/bit64gen.h>
/*! \defgroup bits soft, unpacked and packed bits
* @{
*/
/*! \file bits.h
* \brief Osmocom bit level support code
*
* NOTE on the endianess of pbit_t:
* Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit.
* Bit i in a pbit_t array is array[i/8] & (1<<(7-i%8))
*/
typedef int8_t sbit_t; /*!< \brief soft bit (-127...127) */
typedef uint8_t ubit_t; /*!< \brief unpacked bit (0 or 1) */
typedef uint8_t pbit_t; /*!< \brief packed bis (8 bits in a byte) */
/*! \brief determine how many bytes we would need for \a num_bits packed bits
* \param[in] num_bits Number of packed bits
* \returns number of bytes needed for \a num_bits packed bits
*/
static inline unsigned int osmo_pbit_bytesize(unsigned int num_bits)
{
unsigned int pbit_bytesize = num_bits / 8;
if (num_bits % 8)
pbit_bytesize++;
return pbit_bytesize;
}
int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits);
int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits);
void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
unsigned int num_nibbles);
void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
unsigned int num_nibbles);
void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits);
void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits);
int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
const ubit_t *in, unsigned int in_ofs,
unsigned int num_bits, int lsb_mode);
int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
const pbit_t *in, unsigned int in_ofs,
unsigned int num_bits, int lsb_mode);
#define OSMO_BIN_SPEC "%d%d%d%d%d%d%d%d"
#define OSMO_BIN_PRINT(byte) \
(byte & 0x80 ? 1 : 0), \
(byte & 0x40 ? 1 : 0), \
(byte & 0x20 ? 1 : 0), \
(byte & 0x10 ? 1 : 0), \
(byte & 0x08 ? 1 : 0), \
(byte & 0x04 ? 1 : 0), \
(byte & 0x02 ? 1 : 0), \
(byte & 0x01 ? 1 : 0)
#define OSMO_BIT_SPEC "%c%c%c%c%c%c%c%c"
#define OSMO_BIT_PRINT(byte) \
(byte & 0x80 ? '1' : '.'), \
(byte & 0x40 ? '1' : '.'), \
(byte & 0x20 ? '1' : '.'), \
(byte & 0x10 ? '1' : '.'), \
(byte & 0x08 ? '1' : '.'), \
(byte & 0x04 ? '1' : '.'), \
(byte & 0x02 ? '1' : '.'), \
(byte & 0x01 ? '1' : '.')
/* BIT REVERSAL */
/*! \brief bit-reversal mode for osmo_bit_reversal() */
enum osmo_br_mode {
/*! \brief reverse all bits in a 32bit dword */
OSMO_BR_BITS_IN_DWORD = 31,
/*! \brief reverse byte order in a 32bit dword */
OSMO_BR_BYTES_IN_DWORD = 24,
/*! \brief reverse bits of each byte in a 32bit dword */
OSMO_BR_BITS_IN_BYTE = 7,
/*! \brief swap the two 16bit words in a 32bit dword */
OSMO_BR_WORD_SWAP = 16,
};
/*! \brief generic bit reversal function */
uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k);
/* \brief reverse the bits within each byte of a 32bit word */
uint32_t osmo_revbytebits_32(uint32_t x);
/* \brief reverse the bits within a byte */
uint32_t osmo_revbytebits_8(uint8_t x);
/* \brief reverse the bits of each byte in a given buffer */
void osmo_revbytebits_buf(uint8_t *buf, int len);
/*! \brief left circular shift
* \param[in] in The 16 bit unsigned integer to be rotated
* \param[in] shift Number of bits to shift \a in to, [0;16] bits
* \returns shifted value
*/
static inline uint16_t osmo_rol16(uint16_t in, unsigned shift)
{
return (in << shift) | (in >> (16 - shift));
}
/*! @} */

View File

@@ -0,0 +1,47 @@
#pragma once
/*! \defgroup utils General-purpose utility functions
* @{
*/
/*! \file defs.h
* \brief General definitions that are meant to be included from header files.
*/
/*! \brief Check for gcc and version.
*
* \note Albeit glibc provides a features.h file that contains a similar
* definition (__GNUC_PREREQ), this definition has been copied from there
* to have it available with other libraries, too.
*
* \return != 0 iff gcc is used and it's version is at least maj.min.
*/
#if defined __GNUC__ && defined __GNUC_MINOR__
# define OSMO_GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
# define OSMO_GNUC_PREREQ(maj, min) 0
#endif
/*! \brief Set the deprecated attribute with a message.
*/
#if defined(__clang__)
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED __has_attribute(deprecated)
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE __has_extension(attribute_deprecated_with_message)
#elif defined(__GNUC__)
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED 1
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE OSMO_GNUC_PREREQ(4,5)
#endif
#if _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE
# define OSMO_DEPRECATED(text) __attribute__((__deprecated__(text)))
#elif _OSMO_HAS_ATTRIBUTE_DEPRECATED
# define OSMO_DEPRECATED(text) __attribute__((__deprecated__))
#else
# define OSMO_DEPRECATED(text)
#endif
#undef _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE
#undef _OSMO_HAS_ATTRIBUTE_DEPRECATED
/*! @} */

View File

@@ -0,0 +1,510 @@
#pragma once
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/defs.h>
/*! \defgroup msgb Message buffers
* @{
*/
/*! \file msgb.h
* \brief Osmocom message buffers
* The Osmocom message buffers are modelled after the 'struct skb'
* inside the Linux kernel network stack. As they exist in userspace,
* they are much simplified. However, terminology such as headroom,
* tailroom, push/pull/put etc. remains the same.
*/
#define MSGB_DEBUG
/*! \brief Osmocom message buffer */
struct msgb {
struct llist_head list; /*!< \brief linked list header */
/* Part of which TRX logical channel we were received / transmitted */
/* FIXME: move them into the control buffer */
union {
void *dst; /*!< \brief reference of origin/destination */
struct gsm_bts_trx *trx;
};
struct gsm_lchan *lchan; /*!< \brief logical channel */
unsigned char *l1h; /*!< \brief pointer to Layer1 header (if any) */
unsigned char *l2h; /*!< \brief pointer to A-bis layer 2 header: OML, RSL(RLL), NS */
unsigned char *l3h; /*!< \brief pointer to Layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */
unsigned char *l4h; /*!< \brief pointer to layer 4 header */
unsigned long cb[5]; /*!< \brief control buffer */
uint16_t data_len; /*!< \brief length of underlying data array */
uint16_t len; /*!< \brief length of bytes used in msgb */
unsigned char *head; /*!< \brief start of underlying memory buffer */
unsigned char *tail; /*!< \brief end of message in buffer */
unsigned char *data; /*!< \brief start of message in buffer */
unsigned char _data[0]; /*!< \brief optional immediate data array */
};
extern struct msgb *msgb_alloc(uint16_t size, const char *name);
extern void msgb_free(struct msgb *m);
extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
extern struct msgb *msgb_dequeue(struct llist_head *queue);
extern void msgb_reset(struct msgb *m);
uint16_t msgb_length(const struct msgb *msg);
extern const char *msgb_hexdump(const struct msgb *msg);
extern int msgb_resize_area(struct msgb *msg, uint8_t *area,
int old_size, int new_size);
extern struct msgb *msgb_copy(const struct msgb *msg, const char *name);
static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure));
#ifdef MSGB_DEBUG
#include <osmocom/core/panic.h>
#define MSGB_ABORT(msg, fmt, args ...) do { \
osmo_panic("msgb(%p): " fmt, msg, ## args); \
} while(0)
#else
#define MSGB_ABORT(msg, fmt, args ...)
#endif
/*! \brief obtain L1 header of msgb */
#define msgb_l1(m) ((void *)(m->l1h))
/*! \brief obtain L2 header of msgb */
#define msgb_l2(m) ((void *)(m->l2h))
/*! \brief obtain L3 header of msgb */
#define msgb_l3(m) ((void *)(m->l3h))
/*! \brief obtain SMS header of msgb */
#define msgb_sms(m) ((void *)(m->l4h))
/*! \brief determine length of L1 message
* \param[in] msgb message buffer
* \returns size of L1 message in bytes
*
* This function computes the number of bytes between the tail of the
* message and the layer 1 header.
*/
static inline unsigned int msgb_l1len(const struct msgb *msgb)
{
return msgb->tail - (uint8_t *)msgb_l1(msgb);
}
/*! \brief determine length of L2 message
* \param[in] msgb message buffer
* \returns size of L2 message in bytes
*
* This function computes the number of bytes between the tail of the
* message and the layer 2 header.
*/
static inline unsigned int msgb_l2len(const struct msgb *msgb)
{
return msgb->tail - (uint8_t *)msgb_l2(msgb);
}
/*! \brief determine length of L3 message
* \param[in] msgb message buffer
* \returns size of L3 message in bytes
*
* This function computes the number of bytes between the tail of the
* message and the layer 3 header.
*/
static inline unsigned int msgb_l3len(const struct msgb *msgb)
{
return msgb->tail - (uint8_t *)msgb_l3(msgb);
}
/*! \brief determine the length of the header
* \param[in] msgb message buffer
* \returns number of bytes between start of buffer and start of msg
*
* This function computes the length difference between the underlying
* data buffer and the used section of the \a msgb.
*/
static inline unsigned int msgb_headlen(const struct msgb *msgb)
{
return msgb->len - msgb->data_len;
}
/*! \brief determine how much tail room is left in msgb
* \param[in] msgb message buffer
* \returns number of bytes remaining at end of msgb
*
* This function computes the amount of octets left in the underlying
* data buffer after the end of the message.
*/
static inline int msgb_tailroom(const struct msgb *msgb)
{
return (msgb->head + msgb->data_len) - msgb->tail;
}
/*! \brief determine the amount of headroom in msgb
* \param[in] msgb message buffer
* \returns number of bytes left ahead of message start in msgb
*
* This function computes the amount of bytes left in the underlying
* data buffer before the start of the actual message.
*/
static inline int msgb_headroom(const struct msgb *msgb)
{
return (msgb->data - msgb->head);
}
/*! \brief append data to end of message buffer
* \param[in] msgb message buffer
* \param[in] len number of bytes to append to message
* \returns pointer to start of newly-appended data
*
* This function will move the \a tail pointer of the message buffer \a
* len bytes further, thus enlarging the message by \a len bytes.
*
* The return value is a pointer to start of the newly added section at
* the end of the message and can be used for actually filling/copying
* data into it.
*/
static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
{
unsigned char *tmp = msgb->tail;
if (msgb_tailroom(msgb) < (int) len)
MSGB_ABORT(msgb, "Not enough tailroom msgb_put (%u < %u)\n",
msgb_tailroom(msgb), len);
msgb->tail += len;
msgb->len += len;
return tmp;
}
/*! \brief append a uint8 value to the end of the message
* \param[in] msgb message buffer
* \param[in] word unsigned 8bit byte to be appended
*/
static inline void msgb_put_u8(struct msgb *msgb, uint8_t word)
{
uint8_t *space = msgb_put(msgb, 1);
space[0] = word & 0xFF;
}
/*! \brief append a uint16 value to the end of the message
* \param[in] msgb message buffer
* \param[in] word unsigned 16bit byte to be appended
*/
static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
{
uint8_t *space = msgb_put(msgb, 2);
osmo_store16be(word, space);
}
/*! \brief append a uint32 value to the end of the message
* \param[in] msgb message buffer
* \param[in] word unsigned 32bit byte to be appended
*/
static inline void msgb_put_u32(struct msgb *msgb, uint32_t word)
{
uint8_t *space = msgb_put(msgb, 4);
osmo_store32be(word, space);
}
/*! \brief remove data from end of message
* \param[in] msgb message buffer
* \param[in] len number of bytes to remove from end
*/
static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len)
{
unsigned char *tmp = msgb->tail - len;
if (msgb_length(msgb) < len)
MSGB_ABORT(msgb, "msgb too small to get %u (len %u)\n",
len, msgb_length(msgb));
msgb->tail -= len;
msgb->len -= len;
return tmp;
}
/*! \brief remove uint8 from end of message
* \param[in] msgb message buffer
* \returns 8bit value taken from end of msgb
*/
static inline uint8_t msgb_get_u8(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 1);
return space[0];
}
/*! \brief remove uint16 from end of message
* \param[in] msgb message buffer
* \returns 16bit value taken from end of msgb
*/
static inline uint16_t msgb_get_u16(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 2);
return osmo_load16be(space);
}
/*! \brief remove uint32 from end of message
* \param[in] msgb message buffer
* \returns 32bit value taken from end of msgb
*/
static inline uint32_t msgb_get_u32(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 4);
return osmo_load32be(space);
}
/*! \brief prepend (push) some data to start of message
* \param[in] msgb message buffer
* \param[in] len number of bytes to pre-pend
* \returns pointer to newly added portion at start of \a msgb
*
* This function moves the \a data pointer of the \ref msgb further
* to the front (by \a len bytes), thereby enlarging the message by \a
* len bytes.
*
* The return value is a pointer to the newly added section in the
* beginning of the message. It can be used to fill/copy data into it.
*/
static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
{
if (msgb_headroom(msgb) < (int) len)
MSGB_ABORT(msgb, "Not enough headroom msgb_push (%u < %u)\n",
msgb_headroom(msgb), len);
msgb->data -= len;
msgb->len += len;
return msgb->data;
}
/*! \brief prepend a uint8 value to the head of the message
* \param[in] msgb message buffer
* \param[in] word unsigned 8bit byte to be prepended
*/
static inline void msgb_push_u8(struct msgb *msg, uint8_t word)
{
uint8_t *space = msgb_push(msg, 1);
space[0] = word;
}
/*! \brief prepend a uint16 value to the head of the message
* \param[in] msgb message buffer
* \param[in] word unsigned 16bit byte to be prepended
*/
static inline void msgb_push_u16(struct msgb *msg, uint16_t word)
{
uint16_t *space = (uint16_t *) msgb_push(msg, 2);
osmo_store16be(word, space);
}
/*! \brief prepend a uint32 value to the head of the message
* \param[in] msgb message buffer
* \param[in] word unsigned 32bit byte to be prepended
*/
static inline void msgb_push_u32(struct msgb *msg, uint32_t word)
{
uint32_t *space = (uint32_t *) msgb_push(msg, 4);
osmo_store32be(word, space);
}
/*! \brief remove (pull) a header from the front of the message buffer
* \param[in] msgb message buffer
* \param[in] len number of octets to be pulled
* \returns pointer to new start of msgb
*
* This function moves the \a data pointer of the \ref msgb further back
* in the message, thereby shrinking the size of the message by \a len
* bytes.
*/
static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
{
msgb->len -= len;
return msgb->data += len;
}
/*! \brief remove (pull) all headers in front of l3h from the message buffer.
* \param[in] msgb message buffer with a valid l3h
* \returns pointer to new start of msgb (l3h)
*
* This function moves the \a data pointer of the \ref msgb further back
* in the message, thereby shrinking the size of the message.
* l1h and l2h will be cleared.
*/
static inline unsigned char *msgb_pull_to_l3(struct msgb *msg)
{
unsigned char *ret = msgb_pull(msg, msg->l3h - msg->data);
msg->l1h = msg->l2h = NULL;
return ret;
}
/*! \brief remove (pull) all headers in front of l2h from the message buffer.
* \param[in] msgb message buffer with a valid l2h
* \returns pointer to new start of msgb (l2h)
*
* This function moves the \a data pointer of the \ref msgb further back
* in the message, thereby shrinking the size of the message.
* l1h will be cleared.
*/
static inline unsigned char *msgb_pull_to_l2(struct msgb *msg)
{
unsigned char *ret = msgb_pull(msg, msg->l2h - msg->data);
msg->l1h = NULL;
return ret;
}
/*! \brief remove uint8 from front of message
* \param[in] msgb message buffer
* \returns 8bit value taken from end of msgb
*/
static inline uint8_t msgb_pull_u8(struct msgb *msgb)
{
uint8_t *space = msgb_pull(msgb, 1) - 1;
return space[0];
}
/*! \brief remove uint16 from front of message
* \param[in] msgb message buffer
* \returns 16bit value taken from end of msgb
*/
static inline uint16_t msgb_pull_u16(struct msgb *msgb)
{
uint8_t *space = msgb_pull(msgb, 2) - 2;
return osmo_load16be(space);
}
/*! \brief remove uint32 from front of message
* \param[in] msgb message buffer
* \returns 32bit value taken from end of msgb
*/
static inline uint32_t msgb_pull_u32(struct msgb *msgb)
{
uint8_t *space = msgb_pull(msgb, 4) - 4;
return osmo_load32be(space);
}
/*! \brief Increase headroom of empty msgb, reducing the tailroom
* \param[in] msg message buffer
* \param[in] len amount of extra octets to be reserved as headroom
*
* This function reserves some memory at the beginning of the underlying
* data buffer. The idea is to reserve space in case further headers
* have to be pushed to the \ref msgb during further processing.
*
* Calling this function leads to undefined reusults if it is called on
* a non-empty \ref msgb.
*/
static inline void msgb_reserve(struct msgb *msg, int len)
{
msg->data += len;
msg->tail += len;
}
/*! \brief Trim the msgb to a given absolute length
* \param[in] msg message buffer
* \param[in] len new total length of buffer
* \returns 0 in case of success, negative in case of error
*/
static inline int msgb_trim(struct msgb *msg, int len)
{
if (len < 0)
MSGB_ABORT(msg, "Negative length is not allowed\n");
if (len > msg->data_len)
return -1;
msg->len = len;
msg->tail = msg->data + len;
return 0;
}
/*! \brief Trim the msgb to a given layer3 length
* \param[in] msg message buffer
* \param[in] l3len new layer3 length
* \returns 0 in case of success, negative in case of error
*/
static inline int msgb_l3trim(struct msgb *msg, int l3len)
{
return msgb_trim(msg, (msg->l3h - msg->data) + l3len);
}
/*! \brief Allocate message buffer with specified headroom
* \param[in] size size in bytes, including headroom
* \param[in] headroom headroom in bytes
* \param[in] name human-readable name
* \returns allocated message buffer with specified headroom
*
* This function is a convenience wrapper around \ref msgb_alloc
* followed by \ref msgb_reserve in order to create a new \ref msgb with
* user-specified amount of headroom.
*/
static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
const char *name)
{
osmo_static_assert(size > headroom, headroom_bigger);
struct msgb *msg = msgb_alloc(size, name);
if (msg)
msgb_reserve(msg, headroom);
return msg;
}
/*! \brief Check a message buffer for consistency
* \param[in] msg message buffer
* \returns 0 (false) if inconsistent, != 0 (true) otherwise
*/
static inline int msgb_test_invariant(const struct msgb *msg)
{
const unsigned char *lbound;
if (!msg || !msg->data || !msg->tail ||
(msg->data + msg->len != msg->tail) ||
(msg->data < msg->head) ||
(msg->tail > msg->head + msg->data_len))
return 0;
lbound = msg->head;
if (msg->l1h) {
if (msg->l1h < lbound)
return 0;
lbound = msg->l1h;
}
if (msg->l2h) {
if (msg->l2h < lbound)
return 0;
lbound = msg->l2h;
}
if (msg->l3h) {
if (msg->l3h < lbound)
return 0;
lbound = msg->l3h;
}
if (msg->l4h) {
if (msg->l4h < lbound)
return 0;
lbound = msg->l4h;
}
return lbound <= msg->head + msg->data_len;
}
/* non inline functions to ease binding */
uint8_t *msgb_data(const struct msgb *msg);
void *msgb_talloc_ctx_init(void *root_ctx, unsigned int pool_size);
void msgb_set_talloc_ctx(void *ctx) OSMO_DEPRECATED("Use msgb_talloc_ctx_init() instead");
/*! @} */

View File

@@ -0,0 +1,17 @@
#pragma once
/*! \addtogroup utils
* @{
*/
/*! \file panic.h */
#include <stdarg.h>
/*! \brief panic handler callback function type */
typedef void (*osmo_panic_handler_t)(const char *fmt, va_list args);
extern void osmo_panic(const char *fmt, ...);
extern void osmo_set_panic_handler(osmo_panic_handler_t h);
/*! @} */

View File

@@ -0,0 +1,4 @@
/* Convenience wrapper. libosmocore used to ship its own internal copy of
* talloc, before libtalloc became a standard component on most systems */
#pragma once
#include <talloc.h>

Some files were not shown because too many files have changed in this diff Show More