Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 41 additions & 50 deletions applications/debug/ccid_test/ccid_test_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ typedef enum {

typedef struct {
Gui* gui;
ViewPort* view_port;
FuriMessageQueue* event_queue;
ViewDispatcher* view_dispatcher;
Submenu* submenu;
FuriHalUsbCcidConfig ccid_cfg;
Iso7816Handler* iso7816_handler;
} CcidTestApp;
Expand All @@ -33,30 +33,23 @@ typedef struct {
EventType type;
} CcidTestAppEvent;

typedef enum {
CcidTestAppViewSubmenu,
} CcidTestAppView;

typedef enum {
CcidTestSubmenuIndexInsertSmartcard,
CcidTestSubmenuIndexRemoveSmartcard,
CcidTestSubmenuIndexInsertSmartcardReader
} SubmenuIndex;

static void ccid_test_app_render_callback(Canvas* canvas, void* ctx) {
UNUSED(ctx);
canvas_clear(canvas);

canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 0, 10, "CCID Test App");

canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 0, 63, "Hold [back] to exit");
}

static void ccid_test_app_input_callback(InputEvent* input_event, void* ctx) {
FuriMessageQueue* event_queue = ctx;

CcidTestAppEvent event;
event.type = EventTypeInput;
event.input = *input_event;
furi_message_queue_put(event_queue, &event, FuriWaitForever);
static void ccid_test_submenu_callback(void* context, uint32_t index) {
furi_assert(context);
if(index == CcidTestSubmenuIndexInsertSmartcard) {
furi_hal_usb_ccid_insert_smartcard();
} else if(index == CcidTestSubmenuIndexRemoveSmartcard) {
furi_hal_usb_ccid_remove_smartcard();
}
}

uint32_t ccid_test_exit(void* context) {
Expand All @@ -79,27 +72,39 @@ CcidTestApp* ccid_test_app_alloc(void) {
// Gui
app->gui = furi_record_open(RECORD_GUI);

//viewport
app->view_port = view_port_alloc();
gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);
view_port_draw_callback_set(app->view_port, ccid_test_app_render_callback, NULL);

//message queue
app->event_queue = furi_message_queue_alloc(8, sizeof(CcidTestAppEvent));
view_port_input_callback_set(app->view_port, ccid_test_app_input_callback, app->event_queue);

// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);

// Views
app->submenu = submenu_alloc();
submenu_add_item(
app->submenu,
"Insert smartcard",
CcidTestSubmenuIndexInsertSmartcard,
ccid_test_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Remove smartcard",
CcidTestSubmenuIndexRemoveSmartcard,
ccid_test_submenu_callback,
app);
view_set_previous_callback(submenu_get_view(app->submenu), ccid_test_exit);
view_dispatcher_add_view(
app->view_dispatcher, CcidTestAppViewSubmenu, submenu_get_view(app->submenu));

// Switch to menu
view_dispatcher_switch_to_view(app->view_dispatcher, CcidTestAppViewSubmenu);
return app;
}

void ccid_test_app_free(CcidTestApp* app) {
furi_assert(app);

//message queue
furi_message_queue_free(app->event_queue);

//view port
gui_remove_view_port(app->gui, app->view_port);
view_port_free(app->view_port);
// Free views
view_dispatcher_remove_view(app->view_dispatcher, CcidTestAppViewSubmenu);
submenu_free(app->submenu);

// Close gui record
furi_record_close(RECORD_GUI);
Expand All @@ -124,21 +129,7 @@ int32_t ccid_test_app(void* p) {
iso7816_handler_set_usb_ccid_callbacks();
furi_hal_usb_ccid_insert_smartcard();

//handle button events
CcidTestAppEvent event;
while(1) {
FuriStatus event_status =
furi_message_queue_get(app->event_queue, &event, FuriWaitForever);

if(event_status == FuriStatusOk) {
if(event.type == EventTypeInput) {
if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) {
break;
}
}
}
view_port_update(app->view_port);
}
view_dispatcher_run(app->view_dispatcher);

//tear down USB
iso7816_handler_reset_usb_ccid_callbacks();
Expand Down
68 changes: 63 additions & 5 deletions targets/f7/furi_hal/furi_hal_usb_ccid.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
#define CCID_DATABLOCK_SIZE \
(4 + 1 + CCID_SHORT_APDU_SIZE + 1) //APDU Header + Lc + Short APDU size + Le

#define ENDPOINT_DIR_IN (0x80)
#define ENDPOINT_DIR_OUT (0x00)
#define ENDPOINT_DIR_IN (0x80)
#define ENDPOINT_DIR_OUT (0x00)
#define ENDPOINT_DIR_INTERRUPT (0x40)

#define INTERFACE_ID_CCID (0)

Expand All @@ -31,6 +32,8 @@
/** Endpoint address of the CCID data OUT endpoint, for host-to-device data transfers. */
#define CCID_OUT_EPADDR (ENDPOINT_DIR_OUT | 1)

#define CCID_INTERRUPT_EPADDR (ENDPOINT_DIR_INTERRUPT | 2)

/** Endpoint size in bytes of the CCID data being sent between IN and OUT endpoints. */
#define CCID_EPSIZE 64

Expand All @@ -39,6 +42,7 @@ struct CcidIntfDescriptor {
struct usb_ccid_descriptor ccid_desc;
struct usb_endpoint_descriptor ccid_bulk_in;
struct usb_endpoint_descriptor ccid_bulk_out;
struct usb_endpoint_descriptor ccid_interrupt;
} FURI_PACKED;

struct CcidConfigDescriptor {
Expand Down Expand Up @@ -67,6 +71,8 @@ enum CCID_Features_ExchangeLevel_t {
typedef enum {
WorkerEvtStop = (1 << 0),
WorkerEvtRequest = (1 << 1),
WorkerEvtInsertSmartcard = (1 << 2),
WorkerEvtRemoveSmartcard = (1 << 3),
} WorkerEvtFlags;

typedef struct ccid_bulk_message_header {
Expand Down Expand Up @@ -145,7 +151,7 @@ static const struct CcidConfigDescriptor ccid_cfg_desc = {
CCID_Features_Auto_ParameterConfiguration |
CCID_Features_Auto_ICCActivation |
CCID_Features_Auto_VoltageSelection,
.dwMaxCCIDMessageLength = 0x0c00,
.dwMaxCCIDMessageLength = sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE,
.bClassGetResponse = 0xff,
.bClassEnvelope = 0xff,
.wLcdLayout = 0,
Expand All @@ -167,6 +173,13 @@ static const struct CcidConfigDescriptor ccid_cfg_desc = {
.bmAttributes = USB_EPTYPE_BULK,
.wMaxPacketSize = CCID_EPSIZE,
.bInterval = 0x05},
.ccid_interrupt =
{.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DTYPE_ENDPOINT,
.bEndpointAddress = CCID_INTERRUPT_EPADDR,
.bmAttributes = USB_EPTYPE_INTERRUPT,
.wMaxPacketSize = CCID_EPSIZE,
.bInterval = 0x05},
},
};

Expand Down Expand Up @@ -437,16 +450,32 @@ void CALLBACK_CCID_XfrBlock(
}
}

void CCID_NotifySlotChange(
struct rdr_to_pc_notify_slot_change* message,
uint8_t slot,
bool inserted) {
if(slot == CCID_SLOT_INDEX && inserted != furi_hal_usb_ccid->smartcard_inserted) {
message->bMessageType = RDR_TO_PC_NOTIFYSLOTCHANGE;
if(inserted) {
message->bmSlotICCState[0] = 0x40; //ICC inserted for slot 0
} else {
message->bmSlotICCState[0] = 0x80; //ICC removed for slot 0
}
}
}

void furi_hal_usb_ccid_insert_smartcard(void) {
furi_check(furi_hal_usb_ccid);

furi_hal_usb_ccid->smartcard_inserted = true;
furi_thread_flags_set(
furi_thread_get_id(furi_hal_usb_ccid->ccid_thread), WorkerEvtInsertSmartcard);
}

void furi_hal_usb_ccid_remove_smartcard(void) {
furi_check(furi_hal_usb_ccid);

furi_hal_usb_ccid->smartcard_inserted = false;
furi_thread_flags_set(
furi_thread_get_id(furi_hal_usb_ccid->ccid_thread), WorkerEvtRemoveSmartcard);
}

void furi_hal_usb_ccid_set_callbacks(CcidCallbacks* cb, void* context) {
Expand Down Expand Up @@ -603,6 +632,31 @@ static int32_t ccid_worker(void* context) {
}
} else if(flags & WorkerEvtStop) {
break;
} else if(flags & WorkerEvtInsertSmartcard) {
if(!furi_hal_usb_ccid->smartcard_inserted) {
struct rdr_to_pc_notify_slot_change* responseNotifySlotChange =
(struct rdr_to_pc_notify_slot_change*)&furi_hal_usb_ccid->send_buffer;

CCID_NotifySlotChange(responseNotifySlotChange, CCID_SLOT_INDEX, true);

usbd_ep_write(
furi_hal_usb_ccid->usb_dev,
CCID_INTERRUPT_EPADDR,
furi_hal_usb_ccid->send_buffer,
sizeof(struct rdr_to_pc_notify_slot_change) + sizeof(uint8_t));
}
} else if(flags & WorkerEvtRemoveSmartcard) {
if(furi_hal_usb_ccid->smartcard_inserted) {
struct rdr_to_pc_notify_slot_change* responseNotifySlotChange =
(struct rdr_to_pc_notify_slot_change*)&furi_hal_usb_ccid->send_buffer;

CCID_NotifySlotChange(responseNotifySlotChange, CCID_SLOT_INDEX, false);
usbd_ep_write(
furi_hal_usb_ccid->usb_dev,
CCID_INTERRUPT_EPADDR,
furi_hal_usb_ccid->send_buffer,
sizeof(struct rdr_to_pc_notify_slot_change) + sizeof(uint8_t));
}
}
}
return 0;
Expand All @@ -615,13 +669,17 @@ static usbd_respond ccid_ep_config(usbd_device* dev, uint8_t cfg) {
/* deconfiguring device */
usbd_ep_deconfig(dev, CCID_IN_EPADDR);
usbd_ep_deconfig(dev, CCID_OUT_EPADDR);
usbd_ep_deconfig(dev, CCID_INTERRUPT_EPADDR);

usbd_reg_endpoint(dev, CCID_IN_EPADDR, 0);
usbd_reg_endpoint(dev, CCID_OUT_EPADDR, 0);
return usbd_ack;
case 1:
/* configuring device */
usbd_ep_config(dev, CCID_IN_EPADDR, USB_EPTYPE_BULK, CCID_EPSIZE);
usbd_ep_config(dev, CCID_OUT_EPADDR, USB_EPTYPE_BULK, CCID_EPSIZE);
usbd_ep_config(dev, CCID_INTERRUPT_EPADDR, USB_EPTYPE_INTERRUPT, CCID_EPSIZE);

usbd_reg_endpoint(dev, CCID_IN_EPADDR, ccid_rx_ep_callback);
usbd_reg_endpoint(dev, CCID_OUT_EPADDR, ccid_tx_ep_callback);
return usbd_ack;
Expand Down