Add Initial CCID support (#3048)
* Add Initial CCID support * Sync api symbols * Format sources Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									182c8defb1
								
							
						
					
					
						commit
						a089aeb2bd
					
				
							
								
								
									
										16
									
								
								applications/debug/ccid_test/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								applications/debug/ccid_test/application.fam
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					App(
 | 
				
			||||||
 | 
					    appid="ccid_test",
 | 
				
			||||||
 | 
					    name="CCID Debug",
 | 
				
			||||||
 | 
					    apptype=FlipperAppType.DEBUG,
 | 
				
			||||||
 | 
					    entry_point="ccid_test_app",
 | 
				
			||||||
 | 
					    cdefines=["CCID_TEST"],
 | 
				
			||||||
 | 
					    requires=[
 | 
				
			||||||
 | 
					        "gui",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    provides=[
 | 
				
			||||||
 | 
					        "ccid_test",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    stack_size=1 * 1024,
 | 
				
			||||||
 | 
					    order=120,
 | 
				
			||||||
 | 
					    fap_category="Debug",
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										159
									
								
								applications/debug/ccid_test/ccid_test_app.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								applications/debug/ccid_test/ccid_test_app.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,159 @@
 | 
				
			|||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <furi.h>
 | 
				
			||||||
 | 
					#include <furi_hal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gui/view.h>
 | 
				
			||||||
 | 
					#include <gui/view_dispatcher.h>
 | 
				
			||||||
 | 
					#include <gui/modules/submenu.h>
 | 
				
			||||||
 | 
					#include <gui/gui.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "iso7816_t0_apdu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    EventTypeInput,
 | 
				
			||||||
 | 
					} EventType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    Gui* gui;
 | 
				
			||||||
 | 
					    ViewPort* view_port;
 | 
				
			||||||
 | 
					    FuriMessageQueue* event_queue;
 | 
				
			||||||
 | 
					    FuriHalUsbCcidConfig ccid_cfg;
 | 
				
			||||||
 | 
					} CcidTestApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        InputEvent input;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    EventType type;
 | 
				
			||||||
 | 
					} CcidTestAppEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    CcidTestSubmenuIndexInsertSmartcard,
 | 
				
			||||||
 | 
					    CcidTestSubmenuIndexRemoveSmartcard,
 | 
				
			||||||
 | 
					    CcidTestSubmenuIndexInsertSmartcardReader
 | 
				
			||||||
 | 
					} SubmenuIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen, void* context) {
 | 
				
			||||||
 | 
					    UNUSED(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iso7816_answer_to_reset(atrBuffer, atrlen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void xfr_datablock_callback(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context) {
 | 
				
			||||||
 | 
					    UNUSED(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct ISO7816_Response_APDU responseAPDU;
 | 
				
			||||||
 | 
					    //class not supported
 | 
				
			||||||
 | 
					    responseAPDU.SW1 = 0x6E;
 | 
				
			||||||
 | 
					    responseAPDU.SW2 = 0x00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iso7816_write_response_apdu(&responseAPDU, dataBlock, dataBlockLen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const CcidCallbacks ccid_cb = {
 | 
				
			||||||
 | 
					    icc_power_on_callback,
 | 
				
			||||||
 | 
					    xfr_datablock_callback,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t ccid_test_exit(void* context) {
 | 
				
			||||||
 | 
					    UNUSED(context);
 | 
				
			||||||
 | 
					    return VIEW_NONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CcidTestApp* ccid_test_app_alloc() {
 | 
				
			||||||
 | 
					    CcidTestApp* app = malloc(sizeof(CcidTestApp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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));
 | 
				
			||||||
 | 
					    furi_check(app->event_queue);
 | 
				
			||||||
 | 
					    view_port_input_callback_set(app->view_port, ccid_test_app__input_callback, app->event_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Close gui record
 | 
				
			||||||
 | 
					    furi_record_close(RECORD_GUI);
 | 
				
			||||||
 | 
					    app->gui = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Free rest
 | 
				
			||||||
 | 
					    free(app);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t ccid_test_app(void* p) {
 | 
				
			||||||
 | 
					    UNUSED(p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //setup view
 | 
				
			||||||
 | 
					    CcidTestApp* app = ccid_test_app_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //setup CCID USB
 | 
				
			||||||
 | 
					    // On linux: set VID PID using: /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
 | 
				
			||||||
 | 
					    app->ccid_cfg.vid = 0x1234;
 | 
				
			||||||
 | 
					    app->ccid_cfg.pid = 0x5678;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
 | 
				
			||||||
 | 
					    furi_hal_usb_unlock();
 | 
				
			||||||
 | 
					    furi_hal_ccid_set_callbacks((CcidCallbacks*)&ccid_cb);
 | 
				
			||||||
 | 
					    furi_check(furi_hal_usb_set_config(&usb_ccid, &app->ccid_cfg) == true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //tear down USB
 | 
				
			||||||
 | 
					    furi_hal_usb_set_config(usb_mode_prev, NULL);
 | 
				
			||||||
 | 
					    furi_hal_ccid_set_callbacks(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //teardown view
 | 
				
			||||||
 | 
					    ccid_test_app_free(app);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								applications/debug/ccid_test/iso7816_t0_apdu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								applications/debug/ccid_test/iso7816_t0_apdu.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					/* Implements rudimentary iso7816-3 support for APDU (T=0) */
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <furi.h>
 | 
				
			||||||
 | 
					#include "iso7816_t0_apdu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen) {
 | 
				
			||||||
 | 
					    //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00
 | 
				
			||||||
 | 
					    uint8_t AtrBuffer[2] = {
 | 
				
			||||||
 | 
					        0x3B, //TS (direct convention)
 | 
				
			||||||
 | 
					        0x00 // T0 (Y(1): b0000, K: 0 (historical bytes))
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    *atrlen = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(atrBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iso7816_read_command_apdu(
 | 
				
			||||||
 | 
					    struct ISO7816_Command_APDU* command,
 | 
				
			||||||
 | 
					    const uint8_t* dataBuffer,
 | 
				
			||||||
 | 
					    uint32_t dataLen) {
 | 
				
			||||||
 | 
					    furi_assert(dataLen <= 4);
 | 
				
			||||||
 | 
					    command->CLA = dataBuffer[0];
 | 
				
			||||||
 | 
					    command->INS = dataBuffer[1];
 | 
				
			||||||
 | 
					    command->P1 = dataBuffer[2];
 | 
				
			||||||
 | 
					    command->P2 = dataBuffer[3];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iso7816_write_response_apdu(
 | 
				
			||||||
 | 
					    const struct ISO7816_Response_APDU* response,
 | 
				
			||||||
 | 
					    uint8_t* dataBuffer,
 | 
				
			||||||
 | 
					    uint32_t* dataLen) {
 | 
				
			||||||
 | 
					    dataBuffer[0] = response->SW1;
 | 
				
			||||||
 | 
					    dataBuffer[1] = response->SW2;
 | 
				
			||||||
 | 
					    *dataLen = 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								applications/debug/ccid_test/iso7816_t0_apdu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								applications/debug/ccid_test/iso7816_t0_apdu.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#ifndef _ISO7816_T0_APDU_H_
 | 
				
			||||||
 | 
					#define _ISO7816_T0_APDU_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ISO7816_Command_APDU {
 | 
				
			||||||
 | 
					    //header
 | 
				
			||||||
 | 
					    uint8_t CLA;
 | 
				
			||||||
 | 
					    uint32_t INS;
 | 
				
			||||||
 | 
					    uint8_t P1;
 | 
				
			||||||
 | 
					    uint8_t P2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //body
 | 
				
			||||||
 | 
					    uint8_t Nc;
 | 
				
			||||||
 | 
					    uint8_t Ne;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ISO7816_Response_APDU {
 | 
				
			||||||
 | 
					    uint8_t SW1;
 | 
				
			||||||
 | 
					    uint32_t SW2;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen);
 | 
				
			||||||
 | 
					void iso7816_read_command_apdu(
 | 
				
			||||||
 | 
					    struct ISO7816_Command_APDU* command,
 | 
				
			||||||
 | 
					    const uint8_t* dataBuffer,
 | 
				
			||||||
 | 
					    uint32_t dataLen);
 | 
				
			||||||
 | 
					void iso7816_write_response_apdu(
 | 
				
			||||||
 | 
					    const struct ISO7816_Response_APDU* response,
 | 
				
			||||||
 | 
					    uint8_t* dataBuffer,
 | 
				
			||||||
 | 
					    uint32_t* dataLen);
 | 
				
			||||||
 | 
					#endif //_ISO7816_T0_APDU_H_
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
entry,status,name,type,params
 | 
					entry,status,name,type,params
 | 
				
			||||||
Version,+,39.0,,
 | 
					Version,+,39.1,,
 | 
				
			||||||
Header,+,applications/services/bt/bt_service/bt.h,,
 | 
					Header,+,applications/services/bt/bt_service/bt.h,,
 | 
				
			||||||
Header,+,applications/services/cli/cli.h,,
 | 
					Header,+,applications/services/cli/cli.h,,
 | 
				
			||||||
Header,+,applications/services/cli/cli_vcp.h,,
 | 
					Header,+,applications/services/cli/cli_vcp.h,,
 | 
				
			||||||
@ -76,6 +76,7 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,,
 | 
				
			|||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,,
 | 
				
			||||||
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb_ccid.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,,
 | 
				
			||||||
@ -105,6 +106,7 @@ Header,+,lib/libusb_stm32/inc/hid_usage_telephony.h,,
 | 
				
			|||||||
Header,+,lib/libusb_stm32/inc/hid_usage_vr.h,,
 | 
					Header,+,lib/libusb_stm32/inc/hid_usage_vr.h,,
 | 
				
			||||||
Header,-,lib/libusb_stm32/inc/stm32_compat.h,,
 | 
					Header,-,lib/libusb_stm32/inc/stm32_compat.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb.h,,
 | 
				
			||||||
 | 
					Header,+,lib/libusb_stm32/inc/usb_ccid.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb_cdc.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb_cdc.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb_cdca.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb_cdca.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb_cdce.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb_cdce.h,,
 | 
				
			||||||
@ -1008,6 +1010,9 @@ Function,+,furi_hal_bus_enable,void,FuriHalBus
 | 
				
			|||||||
Function,+,furi_hal_bus_init_early,void,
 | 
					Function,+,furi_hal_bus_init_early,void,
 | 
				
			||||||
Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus
 | 
					Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus
 | 
				
			||||||
Function,+,furi_hal_bus_reset,void,FuriHalBus
 | 
					Function,+,furi_hal_bus_reset,void,FuriHalBus
 | 
				
			||||||
 | 
					Function,+,furi_hal_ccid_ccid_insert_smartcard,void,
 | 
				
			||||||
 | 
					Function,+,furi_hal_ccid_ccid_remove_smartcard,void,
 | 
				
			||||||
 | 
					Function,+,furi_hal_ccid_set_callbacks,void,CcidCallbacks*
 | 
				
			||||||
Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t
 | 
					Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t
 | 
				
			||||||
Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t
 | 
					Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t
 | 
				
			||||||
Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t"
 | 
					Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t"
 | 
				
			||||||
@ -2692,6 +2697,7 @@ Variable,+,sequence_single_vibro,const NotificationSequence,
 | 
				
			|||||||
Variable,+,sequence_solid_yellow,const NotificationSequence,
 | 
					Variable,+,sequence_solid_yellow,const NotificationSequence,
 | 
				
			||||||
Variable,+,sequence_success,const NotificationSequence,
 | 
					Variable,+,sequence_success,const NotificationSequence,
 | 
				
			||||||
Variable,-,suboptarg,char*,
 | 
					Variable,-,suboptarg,char*,
 | 
				
			||||||
 | 
					Variable,+,usb_ccid,FuriHalUsbInterface,
 | 
				
			||||||
Variable,+,usb_cdc_dual,FuriHalUsbInterface,
 | 
					Variable,+,usb_cdc_dual,FuriHalUsbInterface,
 | 
				
			||||||
Variable,+,usb_cdc_single,FuriHalUsbInterface,
 | 
					Variable,+,usb_cdc_single,FuriHalUsbInterface,
 | 
				
			||||||
Variable,+,usb_hid,FuriHalUsbInterface,
 | 
					Variable,+,usb_hid,FuriHalUsbInterface,
 | 
				
			||||||
 | 
				
			|||||||
		
		
			
  | 
@ -1,5 +1,5 @@
 | 
				
			|||||||
entry,status,name,type,params
 | 
					entry,status,name,type,params
 | 
				
			||||||
Version,+,39.0,,
 | 
					Version,+,39.1,,
 | 
				
			||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
 | 
					Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
 | 
				
			||||||
Header,+,applications/services/bt/bt_service/bt.h,,
 | 
					Header,+,applications/services/bt/bt_service/bt.h,,
 | 
				
			||||||
Header,+,applications/services/cli/cli.h,,
 | 
					Header,+,applications/services/cli/cli.h,,
 | 
				
			||||||
@ -82,6 +82,7 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,,
 | 
				
			|||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,,
 | 
				
			||||||
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb_ccid.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,,
 | 
				
			||||||
Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,,
 | 
					Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,,
 | 
				
			||||||
@ -123,6 +124,7 @@ Header,+,lib/libusb_stm32/inc/hid_usage_telephony.h,,
 | 
				
			|||||||
Header,+,lib/libusb_stm32/inc/hid_usage_vr.h,,
 | 
					Header,+,lib/libusb_stm32/inc/hid_usage_vr.h,,
 | 
				
			||||||
Header,-,lib/libusb_stm32/inc/stm32_compat.h,,
 | 
					Header,-,lib/libusb_stm32/inc/stm32_compat.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb.h,,
 | 
				
			||||||
 | 
					Header,+,lib/libusb_stm32/inc/usb_ccid.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb_cdc.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb_cdc.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb_cdca.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb_cdca.h,,
 | 
				
			||||||
Header,+,lib/libusb_stm32/inc/usb_cdce.h,,
 | 
					Header,+,lib/libusb_stm32/inc/usb_cdce.h,,
 | 
				
			||||||
@ -1079,6 +1081,9 @@ Function,+,furi_hal_bus_enable,void,FuriHalBus
 | 
				
			|||||||
Function,+,furi_hal_bus_init_early,void,
 | 
					Function,+,furi_hal_bus_init_early,void,
 | 
				
			||||||
Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus
 | 
					Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus
 | 
				
			||||||
Function,+,furi_hal_bus_reset,void,FuriHalBus
 | 
					Function,+,furi_hal_bus_reset,void,FuriHalBus
 | 
				
			||||||
 | 
					Function,+,furi_hal_ccid_ccid_insert_smartcard,void,
 | 
				
			||||||
 | 
					Function,+,furi_hal_ccid_ccid_remove_smartcard,void,
 | 
				
			||||||
 | 
					Function,+,furi_hal_ccid_set_callbacks,void,CcidCallbacks*
 | 
				
			||||||
Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t
 | 
					Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t
 | 
				
			||||||
Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t
 | 
					Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t
 | 
				
			||||||
Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t"
 | 
					Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t"
 | 
				
			||||||
@ -3479,6 +3484,7 @@ Variable,+,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder,
 | 
				
			|||||||
Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder,
 | 
					Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder,
 | 
				
			||||||
Variable,+,subghz_protocol_registry,const SubGhzProtocolRegistry,
 | 
					Variable,+,subghz_protocol_registry,const SubGhzProtocolRegistry,
 | 
				
			||||||
Variable,-,suboptarg,char*,
 | 
					Variable,-,suboptarg,char*,
 | 
				
			||||||
 | 
					Variable,+,usb_ccid,FuriHalUsbInterface,
 | 
				
			||||||
Variable,+,usb_cdc_dual,FuriHalUsbInterface,
 | 
					Variable,+,usb_cdc_dual,FuriHalUsbInterface,
 | 
				
			||||||
Variable,+,usb_cdc_single,FuriHalUsbInterface,
 | 
					Variable,+,usb_cdc_single,FuriHalUsbInterface,
 | 
				
			||||||
Variable,+,usb_hid,FuriHalUsbInterface,
 | 
					Variable,+,usb_hid,FuriHalUsbInterface,
 | 
				
			||||||
 | 
				
			|||||||
		
		
			
  | 
							
								
								
									
										498
									
								
								firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										498
									
								
								firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,498 @@
 | 
				
			|||||||
 | 
					#include <furi_hal_version.h>
 | 
				
			||||||
 | 
					#include <furi_hal_usb_i.h>
 | 
				
			||||||
 | 
					#include <furi_hal_usb.h>
 | 
				
			||||||
 | 
					#include <furi_hal_usb_ccid.h>
 | 
				
			||||||
 | 
					#include <furi.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "usb.h"
 | 
				
			||||||
 | 
					#include "usb_ccid.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t USB_DEVICE_NO_CLASS = 0x0;
 | 
				
			||||||
 | 
					static const uint8_t USB_DEVICE_NO_SUBCLASS = 0x0;
 | 
				
			||||||
 | 
					static const uint8_t USB_DEVICE_NO_PROTOCOL = 0x0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FIXED_CONTROL_ENDPOINT_SIZE 8
 | 
				
			||||||
 | 
					#define IF_NUM_MAX 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CCID_VID_DEFAULT 0x1234
 | 
				
			||||||
 | 
					#define CCID_PID_DEFAULT 0xABCD
 | 
				
			||||||
 | 
					#define CCID_TOTAL_SLOTS 1
 | 
				
			||||||
 | 
					#define CCID_SLOT_INDEX 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CCID_DATABLOCK_SIZE 256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ENDPOINT_DIR_IN 0x80
 | 
				
			||||||
 | 
					#define ENDPOINT_DIR_OUT 0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define INTERFACE_ID_CCID 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CCID_IN_EPADDR (ENDPOINT_DIR_IN | 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Endpoint address of the CCID data OUT endpoint, for host-to-device data transfers. */
 | 
				
			||||||
 | 
					#define CCID_OUT_EPADDR (ENDPOINT_DIR_OUT | 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Endpoint size in bytes of the CCID data being sent between IN and OUT endpoints. */
 | 
				
			||||||
 | 
					#define CCID_EPSIZE 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct CcidIntfDescriptor {
 | 
				
			||||||
 | 
					    struct usb_interface_descriptor ccid;
 | 
				
			||||||
 | 
					    struct usb_ccid_descriptor ccid_desc;
 | 
				
			||||||
 | 
					    struct usb_endpoint_descriptor ccid_bulk_in;
 | 
				
			||||||
 | 
					    struct usb_endpoint_descriptor ccid_bulk_out;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct CcidConfigDescriptor {
 | 
				
			||||||
 | 
					    struct usb_config_descriptor config;
 | 
				
			||||||
 | 
					    struct CcidIntfDescriptor intf_0;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum CCID_Features_Auto_t {
 | 
				
			||||||
 | 
					    CCID_Features_Auto_None = 0x0,
 | 
				
			||||||
 | 
					    CCID_Features_Auto_ParameterConfiguration = 0x2,
 | 
				
			||||||
 | 
					    CCID_Features_Auto_ICCActivation = 0x4,
 | 
				
			||||||
 | 
					    CCID_Features_Auto_VoltageSelection = 0x8,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CCID_Features_Auto_ICCClockFrequencyChange = 0x10,
 | 
				
			||||||
 | 
					    CCID_Features_Auto_ICCBaudRateChange = 0x20,
 | 
				
			||||||
 | 
					    CCID_Features_Auto_ParameterNegotiation = 0x40,
 | 
				
			||||||
 | 
					    CCID_Features_Auto_PPS = 0x80,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum CCID_Features_ExchangeLevel_t {
 | 
				
			||||||
 | 
					    CCID_Features_ExchangeLevel_TPDU = 0x00010000,
 | 
				
			||||||
 | 
					    CCID_Features_ExchangeLevel_ShortAPDU = 0x00020000,
 | 
				
			||||||
 | 
					    CCID_Features_ExchangeLevel_ShortExtendedAPDU = 0x00040000
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Device descriptor */
 | 
				
			||||||
 | 
					static struct usb_device_descriptor ccid_device_desc = {
 | 
				
			||||||
 | 
					    .bLength = sizeof(struct usb_device_descriptor),
 | 
				
			||||||
 | 
					    .bDescriptorType = USB_DTYPE_DEVICE,
 | 
				
			||||||
 | 
					    .bcdUSB = VERSION_BCD(2, 0, 0),
 | 
				
			||||||
 | 
					    .bDeviceClass = USB_DEVICE_NO_CLASS,
 | 
				
			||||||
 | 
					    .bDeviceSubClass = USB_DEVICE_NO_SUBCLASS,
 | 
				
			||||||
 | 
					    .bDeviceProtocol = USB_DEVICE_NO_PROTOCOL,
 | 
				
			||||||
 | 
					    .bMaxPacketSize0 = FIXED_CONTROL_ENDPOINT_SIZE,
 | 
				
			||||||
 | 
					    .idVendor = CCID_VID_DEFAULT,
 | 
				
			||||||
 | 
					    .idProduct = CCID_PID_DEFAULT,
 | 
				
			||||||
 | 
					    .bcdDevice = VERSION_BCD(1, 0, 0),
 | 
				
			||||||
 | 
					    .iManufacturer = UsbDevManuf,
 | 
				
			||||||
 | 
					    .iProduct = UsbDevProduct,
 | 
				
			||||||
 | 
					    .iSerialNumber = UsbDevSerial,
 | 
				
			||||||
 | 
					    .bNumConfigurations = 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Device configuration descriptor*/
 | 
				
			||||||
 | 
					static const struct CcidConfigDescriptor ccid_cfg_desc = {
 | 
				
			||||||
 | 
					    .config =
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            .bLength = sizeof(struct usb_config_descriptor),
 | 
				
			||||||
 | 
					            .bDescriptorType = USB_DTYPE_CONFIGURATION,
 | 
				
			||||||
 | 
					            .wTotalLength = sizeof(struct CcidConfigDescriptor),
 | 
				
			||||||
 | 
					            .bNumInterfaces = 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            .bConfigurationValue = 1,
 | 
				
			||||||
 | 
					            .iConfiguration = NO_DESCRIPTOR,
 | 
				
			||||||
 | 
					            .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
 | 
				
			||||||
 | 
					            .bMaxPower = USB_CFG_POWER_MA(100),
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    .intf_0 =
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            .ccid =
 | 
				
			||||||
 | 
					                {.bLength = sizeof(struct usb_interface_descriptor),
 | 
				
			||||||
 | 
					                 .bDescriptorType = USB_DTYPE_INTERFACE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                 .bInterfaceNumber = INTERFACE_ID_CCID,
 | 
				
			||||||
 | 
					                 .bAlternateSetting = 0x00,
 | 
				
			||||||
 | 
					                 .bNumEndpoints = 2,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                 .bInterfaceClass = USB_CLASS_CCID,
 | 
				
			||||||
 | 
					                 .bInterfaceSubClass = 0,
 | 
				
			||||||
 | 
					                 .bInterfaceProtocol = 0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                 .iInterface = NO_DESCRIPTOR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            .ccid_desc =
 | 
				
			||||||
 | 
					                {.bLength = sizeof(struct usb_ccid_descriptor),
 | 
				
			||||||
 | 
					                 .bDescriptorType = USB_DTYPE_CCID_FUNCTIONAL,
 | 
				
			||||||
 | 
					                 .bcdCCID = CCID_CURRENT_SPEC_RELEASE_NUMBER,
 | 
				
			||||||
 | 
					                 .bMaxSlotIndex = 0x00,
 | 
				
			||||||
 | 
					                 .bVoltageSupport = CCID_VOLTAGESUPPORT_5V,
 | 
				
			||||||
 | 
					                 .dwProtocols = 0x01, //T0
 | 
				
			||||||
 | 
					                 .dwDefaultClock = 16000, //16MHz
 | 
				
			||||||
 | 
					                 .dwMaximumClock = 16000, //16MHz
 | 
				
			||||||
 | 
					                 .bNumClockSupported = 0,
 | 
				
			||||||
 | 
					                 .dwDataRate = 307200,
 | 
				
			||||||
 | 
					                 .dwMaxDataRate = 307200,
 | 
				
			||||||
 | 
					                 .bNumDataRatesSupported = 0,
 | 
				
			||||||
 | 
					                 .dwMaxIFSD = 2038,
 | 
				
			||||||
 | 
					                 .dwSynchProtocols = 0,
 | 
				
			||||||
 | 
					                 .dwMechanical = 0,
 | 
				
			||||||
 | 
					                 .dwFeatures = CCID_Features_ExchangeLevel_ShortAPDU |
 | 
				
			||||||
 | 
					                               CCID_Features_Auto_ParameterConfiguration |
 | 
				
			||||||
 | 
					                               CCID_Features_Auto_ICCActivation |
 | 
				
			||||||
 | 
					                               CCID_Features_Auto_VoltageSelection,
 | 
				
			||||||
 | 
					                 .dwMaxCCIDMessageLength = 0x0c00,
 | 
				
			||||||
 | 
					                 .bClassGetResponse = 0xff,
 | 
				
			||||||
 | 
					                 .bClassEnvelope = 0xff,
 | 
				
			||||||
 | 
					                 .wLcdLayout = 0,
 | 
				
			||||||
 | 
					                 .bPINSupport = 0,
 | 
				
			||||||
 | 
					                 .bMaxCCIDBusySlots = 1},
 | 
				
			||||||
 | 
					            .ccid_bulk_in =
 | 
				
			||||||
 | 
					                {.bLength = sizeof(struct usb_endpoint_descriptor),
 | 
				
			||||||
 | 
					                 .bDescriptorType = USB_DTYPE_ENDPOINT,
 | 
				
			||||||
 | 
					                 .bEndpointAddress = CCID_IN_EPADDR,
 | 
				
			||||||
 | 
					                 .bmAttributes = USB_EPTYPE_BULK,
 | 
				
			||||||
 | 
					                 .wMaxPacketSize = CCID_EPSIZE,
 | 
				
			||||||
 | 
					                 .bInterval = 0x05
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            .ccid_bulk_out =
 | 
				
			||||||
 | 
					                {.bLength = sizeof(struct usb_endpoint_descriptor),
 | 
				
			||||||
 | 
					                 .bDescriptorType = USB_DTYPE_ENDPOINT,
 | 
				
			||||||
 | 
					                 .bEndpointAddress = CCID_OUT_EPADDR,
 | 
				
			||||||
 | 
					                 .bmAttributes = USB_EPTYPE_BULK,
 | 
				
			||||||
 | 
					                 .wMaxPacketSize = CCID_EPSIZE,
 | 
				
			||||||
 | 
					                 .bInterval = 0x05},
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 | 
				
			||||||
 | 
					static void ccid_deinit(usbd_device* dev);
 | 
				
			||||||
 | 
					static void ccid_on_wakeup(usbd_device* dev);
 | 
				
			||||||
 | 
					static void ccid_on_suspend(usbd_device* dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FuriHalUsbInterface usb_ccid = {
 | 
				
			||||||
 | 
					    .init = ccid_init,
 | 
				
			||||||
 | 
					    .deinit = ccid_deinit,
 | 
				
			||||||
 | 
					    .wakeup = ccid_on_wakeup,
 | 
				
			||||||
 | 
					    .suspend = ccid_on_suspend,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .dev_descr = (struct usb_device_descriptor*)&ccid_device_desc,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .str_manuf_descr = NULL,
 | 
				
			||||||
 | 
					    .str_prod_descr = NULL,
 | 
				
			||||||
 | 
					    .str_serial_descr = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .cfg_descr = (void*)&ccid_cfg_desc,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static usbd_respond ccid_ep_config(usbd_device* dev, uint8_t cfg);
 | 
				
			||||||
 | 
					static usbd_respond ccid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
 | 
				
			||||||
 | 
					static usbd_device* usb_dev;
 | 
				
			||||||
 | 
					static bool connected = false;
 | 
				
			||||||
 | 
					static bool smartcard_inserted = true;
 | 
				
			||||||
 | 
					static CcidCallbacks* callbacks[CCID_TOTAL_SLOTS] = {NULL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void* ccid_set_string_descr(char* str) {
 | 
				
			||||||
 | 
					    furi_assert(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t len = strlen(str);
 | 
				
			||||||
 | 
					    struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2);
 | 
				
			||||||
 | 
					    dev_str_desc->bLength = len * 2 + 2;
 | 
				
			||||||
 | 
					    dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
 | 
				
			||||||
 | 
					    for(size_t i = 0; i < len; i++) dev_str_desc->wString[i] = str[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return dev_str_desc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
 | 
				
			||||||
 | 
					    UNUSED(intf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FuriHalUsbCcidConfig* cfg = (FuriHalUsbCcidConfig*)ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usb_dev = dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usb_ccid.dev_descr->iManufacturer = 0;
 | 
				
			||||||
 | 
					    usb_ccid.dev_descr->iProduct = 0;
 | 
				
			||||||
 | 
					    usb_ccid.str_manuf_descr = NULL;
 | 
				
			||||||
 | 
					    usb_ccid.str_prod_descr = NULL;
 | 
				
			||||||
 | 
					    usb_ccid.dev_descr->idVendor = CCID_VID_DEFAULT;
 | 
				
			||||||
 | 
					    usb_ccid.dev_descr->idProduct = CCID_PID_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(cfg != NULL) {
 | 
				
			||||||
 | 
					        usb_ccid.dev_descr->idVendor = cfg->vid;
 | 
				
			||||||
 | 
					        usb_ccid.dev_descr->idProduct = cfg->pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(cfg->manuf[0] != '\0') {
 | 
				
			||||||
 | 
					            usb_ccid.str_manuf_descr = ccid_set_string_descr(cfg->manuf);
 | 
				
			||||||
 | 
					            usb_ccid.dev_descr->iManufacturer = UsbDevManuf;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(cfg->product[0] != '\0') {
 | 
				
			||||||
 | 
					            usb_ccid.str_prod_descr = ccid_set_string_descr(cfg->product);
 | 
				
			||||||
 | 
					            usb_ccid.dev_descr->iProduct = UsbDevProduct;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usbd_reg_config(dev, ccid_ep_config);
 | 
				
			||||||
 | 
					    usbd_reg_control(dev, ccid_control);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usbd_connect(dev, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_deinit(usbd_device* dev) {
 | 
				
			||||||
 | 
					    usbd_reg_config(dev, NULL);
 | 
				
			||||||
 | 
					    usbd_reg_control(dev, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(usb_ccid.str_prod_descr);
 | 
				
			||||||
 | 
					    free(usb_ccid.str_serial_descr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_on_wakeup(usbd_device* dev) {
 | 
				
			||||||
 | 
					    UNUSED(dev);
 | 
				
			||||||
 | 
					    connected = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_on_suspend(usbd_device* dev) {
 | 
				
			||||||
 | 
					    UNUSED(dev);
 | 
				
			||||||
 | 
					    connected = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ccid_bulk_message_header {
 | 
				
			||||||
 | 
					    uint8_t bMessageType;
 | 
				
			||||||
 | 
					    uint32_t dwLength;
 | 
				
			||||||
 | 
					    uint8_t bSlot;
 | 
				
			||||||
 | 
					    uint8_t bSeq;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct rdr_to_pc_slot_status responseSlotStatus;
 | 
				
			||||||
 | 
					static struct rdr_to_pc_data_block responseDataBlock;
 | 
				
			||||||
 | 
					static struct rdr_to_pc_parameters_t0 responseParameters;
 | 
				
			||||||
 | 
					uint8_t SendDataBlock[CCID_DATABLOCK_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t CALLBACK_CCID_GetSlotStatus(uint8_t slot, uint8_t* error) {
 | 
				
			||||||
 | 
					    if(slot == CCID_SLOT_INDEX) {
 | 
				
			||||||
 | 
					        *error = CCID_ERROR_NOERROR;
 | 
				
			||||||
 | 
					        if(smartcard_inserted) {
 | 
				
			||||||
 | 
					            return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        *error = CCID_ERROR_SLOTNOTFOUND;
 | 
				
			||||||
 | 
					        return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t
 | 
				
			||||||
 | 
					    CALLBACK_CCID_IccPowerOn(uint8_t slot, uint8_t* atrBuffer, uint32_t* atrlen, uint8_t* error) {
 | 
				
			||||||
 | 
					    if(slot == CCID_SLOT_INDEX) {
 | 
				
			||||||
 | 
					        *error = CCID_ERROR_NOERROR;
 | 
				
			||||||
 | 
					        if(smartcard_inserted) {
 | 
				
			||||||
 | 
					            if(callbacks[CCID_SLOT_INDEX] != NULL) {
 | 
				
			||||||
 | 
					                callbacks[CCID_SLOT_INDEX]->icc_power_on_callback(atrBuffer, atrlen, NULL);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
 | 
				
			||||||
 | 
					                       CCID_ICCSTATUS_PRESENTANDINACTIVE;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        *error = CCID_ERROR_SLOTNOTFOUND;
 | 
				
			||||||
 | 
					        return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t CALLBACK_CCID_XfrBlock(
 | 
				
			||||||
 | 
					    uint8_t slot,
 | 
				
			||||||
 | 
					    uint8_t* dataBlock,
 | 
				
			||||||
 | 
					    uint32_t* dataBlockLen,
 | 
				
			||||||
 | 
					    uint8_t* error) {
 | 
				
			||||||
 | 
					    if(slot == CCID_SLOT_INDEX) {
 | 
				
			||||||
 | 
					        *error = CCID_ERROR_NOERROR;
 | 
				
			||||||
 | 
					        if(smartcard_inserted) {
 | 
				
			||||||
 | 
					            if(callbacks[CCID_SLOT_INDEX] != NULL) {
 | 
				
			||||||
 | 
					                callbacks[CCID_SLOT_INDEX]->xfr_datablock_callback(dataBlock, dataBlockLen, NULL);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
 | 
				
			||||||
 | 
					                       CCID_ICCSTATUS_PRESENTANDINACTIVE;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        *error = CCID_ERROR_SLOTNOTFOUND;
 | 
				
			||||||
 | 
					        return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void furi_hal_ccid_ccid_insert_smartcard() {
 | 
				
			||||||
 | 
					    smartcard_inserted = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void furi_hal_ccid_ccid_remove_smartcard() {
 | 
				
			||||||
 | 
					    smartcard_inserted = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void furi_hal_ccid_set_callbacks(CcidCallbacks* cb) {
 | 
				
			||||||
 | 
					    callbacks[CCID_SLOT_INDEX] = cb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_rx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
 | 
				
			||||||
 | 
					    UNUSED(dev);
 | 
				
			||||||
 | 
					    UNUSED(event);
 | 
				
			||||||
 | 
					    UNUSED(ep);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ccid_tx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
 | 
				
			||||||
 | 
					    UNUSED(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(event == usbd_evt_eprx) {
 | 
				
			||||||
 | 
					        if(connected == false) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        struct ccid_bulk_message_header message;
 | 
				
			||||||
 | 
					        usbd_ep_read(usb_dev, ep, &message, sizeof(message));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t Status;
 | 
				
			||||||
 | 
					        uint8_t Error = CCID_ERROR_NOERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint32_t dataBlockLen = 0;
 | 
				
			||||||
 | 
					        uint8_t* dataBlockBuffer = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(message.bMessageType == PC_TO_RDR_GETSLOTSTATUS) {
 | 
				
			||||||
 | 
					            responseSlotStatus.bMessageType = RDR_TO_PC_SLOTSTATUS;
 | 
				
			||||||
 | 
					            responseSlotStatus.dwLength = 0;
 | 
				
			||||||
 | 
					            responseSlotStatus.bSlot = message.bSlot;
 | 
				
			||||||
 | 
					            responseSlotStatus.bSeq = message.bSeq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseSlotStatus.bClockStatus = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Status = CALLBACK_CCID_GetSlotStatus(message.bSlot, &Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseSlotStatus.bStatus = Status;
 | 
				
			||||||
 | 
					            responseSlotStatus.bError = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            usbd_ep_write(
 | 
				
			||||||
 | 
					                usb_dev, CCID_IN_EPADDR, &responseSlotStatus, sizeof(responseSlotStatus));
 | 
				
			||||||
 | 
					        } else if(message.bMessageType == PC_TO_RDR_ICCPOWERON) {
 | 
				
			||||||
 | 
					            responseDataBlock.bMessageType = RDR_TO_PC_DATABLOCK;
 | 
				
			||||||
 | 
					            responseDataBlock.bSlot = message.bSlot;
 | 
				
			||||||
 | 
					            responseDataBlock.bSeq = message.bSeq;
 | 
				
			||||||
 | 
					            responseDataBlock.bChainParameter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dataBlockLen = 0;
 | 
				
			||||||
 | 
					            dataBlockBuffer = (uint8_t*)SendDataBlock;
 | 
				
			||||||
 | 
					            Status = CALLBACK_CCID_IccPowerOn(
 | 
				
			||||||
 | 
					                message.bSlot, (uint8_t*)dataBlockBuffer, &dataBlockLen, &Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            furi_assert(dataBlockLen < CCID_DATABLOCK_SIZE);
 | 
				
			||||||
 | 
					            responseDataBlock.dwLength = dataBlockLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseSlotStatus.bStatus = Status;
 | 
				
			||||||
 | 
					            responseSlotStatus.bError = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            memcpy(responseDataBlock.abData, SendDataBlock, dataBlockLen);
 | 
				
			||||||
 | 
					            usbd_ep_write(
 | 
				
			||||||
 | 
					                usb_dev,
 | 
				
			||||||
 | 
					                CCID_IN_EPADDR,
 | 
				
			||||||
 | 
					                &responseDataBlock,
 | 
				
			||||||
 | 
					                sizeof(struct rdr_to_pc_data_block) + (sizeof(uint8_t) * dataBlockLen));
 | 
				
			||||||
 | 
					        } else if(message.bMessageType == PC_TO_RDR_ICCPOWEROFF) {
 | 
				
			||||||
 | 
					            responseSlotStatus.bMessageType = RDR_TO_PC_SLOTSTATUS;
 | 
				
			||||||
 | 
					            responseSlotStatus.dwLength = 0;
 | 
				
			||||||
 | 
					            responseSlotStatus.bSlot = message.bSlot;
 | 
				
			||||||
 | 
					            responseSlotStatus.bSeq = message.bSeq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseSlotStatus.bClockStatus = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint8_t Status;
 | 
				
			||||||
 | 
					            uint8_t Error = CCID_ERROR_NOERROR;
 | 
				
			||||||
 | 
					            Status = CALLBACK_CCID_GetSlotStatus(message.bSlot, &Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseSlotStatus.bStatus = Status;
 | 
				
			||||||
 | 
					            responseSlotStatus.bError = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            usbd_ep_write(
 | 
				
			||||||
 | 
					                usb_dev, CCID_IN_EPADDR, &responseSlotStatus, sizeof(responseSlotStatus));
 | 
				
			||||||
 | 
					        } else if(message.bMessageType == PC_TO_RDR_SETPARAMETERS) {
 | 
				
			||||||
 | 
					            responseParameters.bMessageType = RDR_TO_PC_PARAMETERS;
 | 
				
			||||||
 | 
					            responseParameters.bSlot = message.bSlot;
 | 
				
			||||||
 | 
					            responseParameters.bSeq = message.bSeq;
 | 
				
			||||||
 | 
					            responseParameters.bProtocolNum = 0; //T0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint8_t Status = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR;
 | 
				
			||||||
 | 
					            uint8_t Error = CCID_ERROR_NOERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseParameters.bStatus = Status;
 | 
				
			||||||
 | 
					            responseParameters.bError = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseParameters.dwLength = sizeof(struct rdr_to_pc_parameters_t0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            usbd_ep_write(
 | 
				
			||||||
 | 
					                usb_dev, CCID_IN_EPADDR, &responseParameters, sizeof(responseParameters));
 | 
				
			||||||
 | 
					        } else if(message.bMessageType == PC_TO_RDR_XFRBLOCK) {
 | 
				
			||||||
 | 
					            responseDataBlock.bMessageType = RDR_TO_PC_DATABLOCK;
 | 
				
			||||||
 | 
					            responseDataBlock.bSlot = message.bSlot;
 | 
				
			||||||
 | 
					            responseDataBlock.bSeq = message.bSeq;
 | 
				
			||||||
 | 
					            responseDataBlock.bChainParameter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dataBlockLen = 0;
 | 
				
			||||||
 | 
					            dataBlockBuffer = (uint8_t*)SendDataBlock;
 | 
				
			||||||
 | 
					            Status = CALLBACK_CCID_XfrBlock(
 | 
				
			||||||
 | 
					                message.bSlot, (uint8_t*)dataBlockBuffer, &dataBlockLen, &Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            furi_assert(dataBlockLen < CCID_DATABLOCK_SIZE);
 | 
				
			||||||
 | 
					            responseDataBlock.dwLength = dataBlockLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            responseSlotStatus.bStatus = Status;
 | 
				
			||||||
 | 
					            responseSlotStatus.bError = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            memcpy(responseDataBlock.abData, SendDataBlock, dataBlockLen);
 | 
				
			||||||
 | 
					            usbd_ep_write(
 | 
				
			||||||
 | 
					                usb_dev,
 | 
				
			||||||
 | 
					                CCID_IN_EPADDR,
 | 
				
			||||||
 | 
					                &responseDataBlock,
 | 
				
			||||||
 | 
					                sizeof(struct rdr_to_pc_data_block) + (sizeof(uint8_t) * dataBlockLen));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Configure endpoints */
 | 
				
			||||||
 | 
					static usbd_respond ccid_ep_config(usbd_device* dev, uint8_t cfg) {
 | 
				
			||||||
 | 
					    switch(cfg) {
 | 
				
			||||||
 | 
					    case 0:
 | 
				
			||||||
 | 
					        /* deconfiguring device */
 | 
				
			||||||
 | 
					        usbd_ep_deconfig(dev, CCID_IN_EPADDR);
 | 
				
			||||||
 | 
					        usbd_ep_deconfig(dev, CCID_OUT_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_reg_endpoint(dev, CCID_IN_EPADDR, ccid_rx_ep_callback);
 | 
				
			||||||
 | 
					        usbd_reg_endpoint(dev, CCID_OUT_EPADDR, ccid_tx_ep_callback);
 | 
				
			||||||
 | 
					        return usbd_ack;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        return usbd_fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Control requests handler */
 | 
				
			||||||
 | 
					static usbd_respond ccid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
 | 
				
			||||||
 | 
					    UNUSED(callback);
 | 
				
			||||||
 | 
					    /* CDC control requests */
 | 
				
			||||||
 | 
					    if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
 | 
				
			||||||
 | 
					           (USB_REQ_INTERFACE | USB_REQ_CLASS) &&
 | 
				
			||||||
 | 
					       (req->wIndex == 0 || req->wIndex == 2)) {
 | 
				
			||||||
 | 
					        switch(req->bRequest) {
 | 
				
			||||||
 | 
					        case CCID_ABORT:
 | 
				
			||||||
 | 
					            return usbd_fail;
 | 
				
			||||||
 | 
					        case CCID_GET_CLOCK_FREQUENCIES:
 | 
				
			||||||
 | 
					            dev->status.data_ptr = (void*)&(ccid_cfg_desc.intf_0.ccid_desc.dwDefaultClock);
 | 
				
			||||||
 | 
					            dev->status.data_count = sizeof(ccid_cfg_desc.intf_0.ccid_desc.dwDefaultClock);
 | 
				
			||||||
 | 
					            return usbd_ack;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return usbd_fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return usbd_fail;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -35,6 +35,7 @@ struct STOP_EXTERNING_ME {};
 | 
				
			|||||||
#include <furi_hal_vibro.h>
 | 
					#include <furi_hal_vibro.h>
 | 
				
			||||||
#include <furi_hal_usb.h>
 | 
					#include <furi_hal_usb.h>
 | 
				
			||||||
#include <furi_hal_usb_hid.h>
 | 
					#include <furi_hal_usb_hid.h>
 | 
				
			||||||
 | 
					#include <furi_hal_usb_ccid.h>
 | 
				
			||||||
#include <furi_hal_uart.h>
 | 
					#include <furi_hal_uart.h>
 | 
				
			||||||
#include <furi_hal_info.h>
 | 
					#include <furi_hal_info.h>
 | 
				
			||||||
#include <furi_hal_random.h>
 | 
					#include <furi_hal_random.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -28,6 +28,7 @@ extern FuriHalUsbInterface usb_cdc_single;
 | 
				
			|||||||
extern FuriHalUsbInterface usb_cdc_dual;
 | 
					extern FuriHalUsbInterface usb_cdc_dual;
 | 
				
			||||||
extern FuriHalUsbInterface usb_hid;
 | 
					extern FuriHalUsbInterface usb_hid;
 | 
				
			||||||
extern FuriHalUsbInterface usb_hid_u2f;
 | 
					extern FuriHalUsbInterface usb_hid_u2f;
 | 
				
			||||||
 | 
					extern FuriHalUsbInterface usb_ccid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    FuriHalUsbStateEventReset,
 | 
					    FuriHalUsbStateEventReset,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								firmware/targets/furi_hal_include/furi_hal_usb_ccid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								firmware/targets/furi_hal_include/furi_hal_usb_ccid.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include "hid_usage_desktop.h"
 | 
				
			||||||
 | 
					#include "hid_usage_button.h"
 | 
				
			||||||
 | 
					#include "hid_usage_keyboard.h"
 | 
				
			||||||
 | 
					#include "hid_usage_consumer.h"
 | 
				
			||||||
 | 
					#include "hid_usage_led.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    uint16_t vid;
 | 
				
			||||||
 | 
					    uint16_t pid;
 | 
				
			||||||
 | 
					    char manuf[32];
 | 
				
			||||||
 | 
					    char product[32];
 | 
				
			||||||
 | 
					} FuriHalUsbCcidConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    void (*icc_power_on_callback)(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context);
 | 
				
			||||||
 | 
					    void (*xfr_datablock_callback)(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context);
 | 
				
			||||||
 | 
					} CcidCallbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void furi_hal_ccid_set_callbacks(CcidCallbacks* cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void furi_hal_ccid_ccid_insert_smartcard();
 | 
				
			||||||
 | 
					void furi_hal_ccid_ccid_remove_smartcard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -1 +1 @@
 | 
				
			|||||||
Subproject commit 9168e2a31db946326fb84016a74ea2ab5bf87f54
 | 
					Subproject commit 6ca2857519f996244f7b324dd227fdf0a075fffb
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user