root/usr/src/uts/common/sys/usb/clients/ccid/ccid.h
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2019, Joyent, Inc.
 */

#ifndef _SYS_USB_CCID_H
#define _SYS_USB_CCID_H

/*
 * CCID class driver definitions.
 */

#include <sys/stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Values for various Hardware, Mechanical, and Pin features. These come from
 * the device's class descriptor.
 */
typedef enum ccid_class_voltage {
        CCID_CLASS_VOLT_AUTO    = 0x00,
        CCID_CLASS_VOLT_5_0     = 0x01,
        CCID_CLASS_VOLT_3_0     = 0x02,
        CCID_CLASS_VOLT_1_8     = 0x04
} ccid_class_voltage_t;

typedef enum ccid_class_mechanical {
        CCID_CLASS_MECH_CARD_ACCEPT     = 0x01,
        CCID_CLASS_MECH_CARD_EJECT      = 0x02,
        CCID_CLASS_MECH_CARD_CAPTURE    = 0x04,
        CCID_CLASS_MECH_CARD_LOCK       = 0x08
} ccid_class_mechanical_t;

typedef enum ccid_class_features {
        CCID_CLASS_F_AUTO_PARAM_ATR     = 0x00000002,
        CCID_CLASS_F_AUTO_ICC_ACTIVATE  = 0x00000004,
        CCID_CLASS_F_AUTO_ICC_VOLTAGE   = 0x00000008,
        CCID_CLASS_F_AUTO_ICC_CLOCK     = 0x00000010,
        CCID_CLASS_F_AUTO_BAUD          = 0x00000020,
        CCID_CLASS_F_AUTO_PARAM_NEG     = 0x00000040,
        CCID_CLASS_F_AUTO_PPS           = 0x00000080,
        CCID_CLASS_F_ICC_CLOCK_STOP     = 0x00000100,
        CCID_CLASS_F_ALTNAD_SUP         = 0x00000200,
        CCID_CLASS_F_AUTO_IFSD          = 0x00000400,
        CCID_CLASS_F_TPDU_XCHG          = 0x00010000,
        CCID_CLASS_F_SHORT_APDU_XCHG    = 0x00020000,
        CCID_CLASS_F_EXT_APDU_XCHG      = 0x00040000,
        CCID_CLASS_F_WAKE_UP            = 0x00100000
} ccid_class_features_t;

typedef enum ccid_class_pin {
        CCID_CLASS_PIN_VERIFICATION     = 0x01,
        CCID_CLASS_PIN_MODIFICATION     = 0x02
} ccid_class_pin_t;

/*
 * CCID Class Descriptor
 *
 * This structure represents the CCID class descriptor. Note, it should not be a
 * packed structure. This is designed to be a native representation. The raw
 * structure will be parsed into this instead.
 */
typedef struct ccid_class_descr {
        uint8_t         ccd_bLength;
        uint8_t         ccd_bDescriptorType;
        uint16_t        ccd_bcdCCID;
        uint8_t         ccd_bMaxSlotIndex;
        uint8_t         ccd_bVoltageSupport;
        uint32_t        ccd_dwProtocols;
        uint32_t        ccd_dwDefaultClock;
        uint32_t        ccd_dwMaximumClock;
        uint8_t         ccd_bNumClockSupported;
        uint32_t        ccd_dwDataRate;
        uint32_t        ccd_dwMaxDataRate;
        uint8_t         ccd_bNumDataRatesSupported;
        uint32_t        ccd_dwMaxIFSD;
        uint32_t        ccd_dwSyncProtocols;
        uint32_t        ccd_dwMechanical;
        uint32_t        ccd_dwFeatures;
        uint32_t        ccd_dwMaxCCIDMessageLength;
        uint8_t         ccd_bClassGetResponse;
        uint8_t         ccd_bClassEnvelope;
        uint16_t        ccd_wLcdLayout;
        uint8_t         ccd_bPinSupport;
        uint8_t         ccd_bMaxCCIDBusySlots;
} ccid_class_descr_t;

/*
 * Definitions for the supported versions of the CCID specification. The version
 * is encoded in binary encoded decimal. The major version is in the upper 8
 * bits and the minor version is in the lower 8 bits. We currently check for the
 * major version to match.
 */
#define CCID_VERSION_MAJOR(ver) (((ver) & 0xff00) >> 8)
#define CCID_VERSION_MINOR(ver) ((ver) & 0x00ff)
#define CCID_VERSION_ONE        0x01

/*
 * This structure is used as the data for the CCID_REQUEST_SET_PARAMS request
 * and the CCID_RESPONSE_PARAMETERS response. There are different structures for
 * T=0 and T=1. These come from CCID r1.1 / Section 6.1.7.
 */
typedef struct ccid_params_t0 {
        uint8_t cp0_bmFindexDindex;
        uint8_t cp0_bmTCCKST0;
        uint8_t cp0_bGuardTimeT0;
        uint8_t cp0_bWaitingIntegerT0;
        uint8_t cp0_bClockStop;
} __packed ccid_params_t0_t;

#define CCID_P_TCCKST0_DIRECT   0x00
#define CCID_P_TCCKST0_INVERSE  0x02

typedef struct ccid_params_t1 {
        uint8_t cp1_bmFindexDindex;
        uint8_t cp1_bmTCCKST1;
        uint8_t cp1_bGuardTimeT1;
        uint8_t cp1_bmWaitingIntegersT1;
        uint8_t cp1_bClockStop;
        uint8_t cp1_bIFSC;
        uint8_t cp1_bNadValue;
} __packed ccid_params_t1_t;

typedef union ccid_params {
        ccid_params_t0_t ccp_t0;
        ccid_params_t1_t ccp_t1;
} ccid_params_t;

#define CCID_P_FI_DI(fi, di)    ((((fi) & 0x0f) << 4) | ((di) & 0x0f))

/*
 * Everything below this point is reserved for the kernel.
 */
#ifdef  _KERNEL

/*
 * These values come from CCID r1.1.0 Table 5.1-1 'Smart Card Device
 * Descriptors'
 */
#define CCID_DESCR_TYPE         0x21
#define CCID_DESCR_LENGTH       0x36


/*
 * Minimum and maximum value for a sequence number in the CCID specification.
 * The sequence is a 1 byte unsigned value. The values are inclusive. We reserve
 * the value of 0x00 so that we can use it as a sentinel in the ccid_command_t
 * structure to know when we should or shouldn't free a command structure's
 * sequence number back to the id space.
 */
#define CCID_SEQ_MIN    0x01
#define CCID_SEQ_MAX    UINT8_MAX


/*
 * All structures from the specification must be packed.
 */

/*
 * Interrupt-IN messages codes.
 */
typedef enum ccid_intr_code {
        CCID_INTR_CODE_SLOT_CHANGE      = 0x50,
        CCID_INTR_CODE_HW_ERROR         = 0x51
} ccid_intr_code_t;

typedef enum ccid_intr_hwerr_code {
        CCID_INTR_HWERR_OVERCURRENT     = 0x01
} ccid_intr_hwerr_code_t;

typedef struct ccid_intr_slot {
        uint8_t cis_type;
        uint8_t cis_state[];
} ccid_intr_slot_t;

typedef struct ccid_intr_hwerr {
        uint8_t cih_type;
        uint8_t cih_slot;
        uint8_t cih_seq;
        uint8_t cih_code;
} ccid_intr_hwerr_t;

/*
 * Message request codes. These codes are based on CCID r1.1.0 Table 6.1-1
 * 'Summary of Bulk-Out Messages'. The name from the standard is to the right of
 * the enum.
 */
typedef enum ccid_request_code {
        CCID_REQUEST_POWER_ON           = 0x62, /* PC_to_RDR_IccPowerOn */
        CCID_REQUEST_POWER_OFF          = 0x63, /* PC_to_RDR_IccPowerOff */
        CCID_REQUEST_SLOT_STATUS        = 0x65, /* PC_to_RDR_GetSlotStatus */
        CCID_REQUEST_TRANSFER_BLOCK     = 0x6f, /* PC_to_RDR_XfrBlock */
        CCID_REQUEST_GET_PARAMS         = 0x6c, /* PC_to_RDR_GetParameters */
        CCID_REQUEST_RESET_PARAMS       = 0x6d, /* PC_to_RDR_ResetParameters */
        CCID_REQUEST_SET_PARAMS         = 0x61, /* PC_to_RDR_SetParameters */
        CCID_REQUEST_ESCAPE             = 0x6b, /* PC_to_RDR_Escape */
        CCID_REQUEST_ICC_CLOCK          = 0x6e, /* PC_to_RDR_IccClock */
        CCID_REQUEST_T0APDU             = 0x6a, /* PC_to_RDR_T0APDU */
        CCID_REQUEST_SECURE             = 0x69, /* PC_to_RDR_Secure */
        CCID_REQUEST_MECHANICAL         = 0x71, /* PC_to_RDR_Mechanica */
        CCID_REQEUST_ABORT              = 0x72, /* PC_to_RDR_Abort */
        CCID_REQUEST_DATA_CLOCK         = 0x73  /* PC_to_RDR_SetDataRateAnd */
                                                /* ClockFrequency */
} ccid_request_code_t;

/*
 * Message request codes. These codes are based on CCID r1.1.0 Table 6.2-1
 * 'Summary of Bulk-In Messages'. The name from the standard is to the right of
 * the enum.
 */
typedef enum ccid_response_code {
        CCID_RESPONSE_DATA_BLOCK        = 0x80, /* RDR_to_PC_DataBlock */
        CCID_RESPONSE_SLOT_STATUS       = 0x81, /* RDR_to_PC_SlotStatus */
        CCID_RESPONSE_PARAMETERS        = 0x82, /* RDR_to_PC_Parameters */
        CCID_RESPONSE_ESCAPE            = 0x83, /* RDR_to_PC_Escape */
        CCID_RESPONSE_DATA_CLOCK        = 0x84  /* RDR_to_PC_DataRateAnd */
                                                /* ClockFrequency */
} ccid_response_code_t;

/*
 * This represents the CCID command header that is used for every request and
 * response.
 */
typedef struct ccid_header {
        uint8_t         ch_mtype;
        uint32_t        ch_length;      /* Length of ch_data in bytes */
        uint8_t         ch_slot;        /* CCID slot to target */
        uint8_t         ch_seq;         /* Request/Response sequence num */
        uint8_t         ch_param0;      /* Request/Response specific */
        uint8_t         ch_param1;      /* Request/Response specific */
        uint8_t         ch_param2;      /* Request/Response specific */
        uint8_t         ch_data[];      /* Optional Request/Response Data */
} __packed ccid_header_t;

/*
 * This structure is used as the data for the CCID_REQUEST_DATA_CLOCK and
 * CCID_RESPONSE_DATA_CLOCK commands.
 */
typedef struct ccid_data_clock {
        uint32_t        cdc_clock;
        uint32_t        cdc_data;
} __packed ccid_data_clock_t;

/*
 * Macros and constants to take apart the slot status (in ch_param1) when a CCID
 * reply comes in.
 */
#define CCID_REPLY_ICC(x)       (x & 0x3)
#define CCID_REPLY_STATUS(x)    ((x & 0xc0) >> 6)

typedef enum {
        CCID_REPLY_ICC_ACTIVE = 0,
        CCID_REPLY_ICC_INACTIVE,
        CCID_REPLY_ICC_MISSING
} ccid_reply_icc_status_t;

typedef enum {
        CCID_REPLY_STATUS_COMPLETE = 0,
        CCID_REPLY_STATUS_FAILED,
        CCID_REPLY_STATUS_MORE_TIME
} ccid_reply_command_status_t;

/*
 * Errors that are defined based when commands fail. These are based on CCID
 * r.1.1.0 Table 6.2-2 'Slot error register when bmCommandStatus = 1'.
 */
typedef enum ccid_command_err {
        CCID_ERR_CMD_ABORTED                    = 0xff,
        CCID_ERR_ICC_MUTE                       = 0xfe,
        CCID_ERR_XFR_PARITY_ERROR               = 0xfd,
        CCID_ERR_XFR_OVERRUN                    = 0xfc,
        CCID_ERR_HW_ERROR                       = 0xfb,
        CCID_ERR_BAD_ATR_TS                     = 0xf8,
        CCID_ERR_BAD_ATR_TCK                    = 0xf7,
        CCID_ERR_ICC_PROTOCOL_NOT_SUPPORTED     = 0xf6,
        CCID_ERR_ICC_CLASS_NOT_SUPPORTED        = 0xf5,
        CCID_ERR_PROCEDURE_BYTE_CONFLICT        = 0xf4,
        CCID_ERR_DEACTIVATED_PROTOCOL           = 0xf3,
        CCID_ERR_BUSY_WITH_AUTO_SEQUENCE        = 0xf2,
        CCID_ERR_PIN_TIMEOUT                    = 0xf0,
        CCID_ERR_PIN_CANCELLED                  = 0xef,
        CCID_ERR_CMD_SLOT_BUSY                  = 0xe0,
        CCID_ERR_CMD_NOT_SUPPORTED              = 0x00
} ccid_command_err_t;

/*
 * Maximum size of an APDU (application data unit) payload. There are both short
 * and extended ADPUs. At this time, we only support the short ADPUs.
 */
#define CCID_APDU_LEN_MAX       261

#endif  /* _KERNEL */

#ifdef __cplusplus
}
#endif

#endif /* _SYS_USB_CCID_H */