aboutsummaryrefslogtreecommitdiffstats
path: root/ccid/ccid_device.h
blob: d9cba52f6e336595c9b0960323575e3141486cef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#pragma once
#include <stdbool.h>
#include <stdint.h>

#include "ccid_proto.h"

enum {
	DCCID,
	DUSB,
};

#define NR_SLOTS	8

#define LOGPCI(ci, lvl, fmt, args ...) LOGP(DCCID, lvl, "%s: " fmt, (ci)->name, ## args)
#define LOGPCS(cs, lvl, fmt, args ...) \
	LOGP(DCCID, lvl, "%s(%u): " fmt, (cs)->ci->name, (cs)->slot_nr, ## args)

struct msgb;

struct ccid_pars_decoded {
	/* global for T0/T1 */
	uint8_t fi;
	uint8_t di;
	enum ccid_clock_stop clock_stop;
	bool inverse_convention;

	struct {
		uint8_t guard_time_etu;
		uint8_t waiting_integer;
	} t0;

	struct {
		enum ccid_t1_csum_type csum_type;
		uint8_t guard_time_t1;
		uint8_t bwi;
		uint8_t cwi;
		uint8_t ifsc;
		uint8_t nad;
	} t1;
};

struct ccid_slot {
	/* back-pointer to the ccid_instance */
	struct ccid_instance *ci;
	/* number of this slot (0 = first) */
	uint8_t slot_nr;
	/* is there an ICC physically present (card detect)? */
	bool icc_present;
	/* was there an ICC present during the last NotifSlotStatus?
	 * should be set to zero every USB resume and setConfig != 0 */
	bool icc_present_last;
	/* is the ICC physically powered? */
	bool icc_powered;
	/* is the ICC currently in reset? */
	bool icc_in_reset;
	/* is this slot currently busy with processing a CCID command? */
	bool cmd_busy;
	/* decided CCID parameters */
	struct ccid_pars_decoded pars;
	/* default parameters; applied on ResetParameters */
	const struct ccid_pars_decoded *default_pars;
};

/* CCID operations provided by USB transport layer */
struct ccid_ops {
	/* msgb ownership in below functions is transferred, i.e. whoever
	 * provides the callback function must make sure to msgb_free() them
	 * once transmission on IN or INT EP has completed. */
	int (*send_in)(struct ccid_instance *ci, struct msgb *msg);
	int (*send_int)(struct ccid_instance *ci, struct msgb *msg);
};

/* CCID operations provided by actual slot hardware */
struct ccid_slot_ops {
	/* called once on start-up for initialization */
	int (*init)(struct ccid_slot *cs);
	/* called before processing any command for a slot; used e.g. to
	 * update the (power/clock/...) status from the hardware */
	void (*pre_proc_cb)(struct ccid_slot *cs, struct msgb *msg);

	void (*icc_power_on_async)(struct ccid_slot *cs, struct msgb *msg,
				   const struct ccid_pc_to_rdr_icc_power_on *ipo);
	void (*xfr_block_async)(struct ccid_slot *cs, struct msgb *msg,
				const struct ccid_pc_to_rdr_xfr_block *xfb);
	void (*set_power)(struct ccid_slot *cs, bool enable);
	void (*set_clock)(struct ccid_slot *cs, enum ccid_clock_command cmd);
	int (*set_params)(struct ccid_slot *cs, enum ccid_protocol_num proto,
			  const struct ccid_pars_decoded *pars_dec);
	int (*set_rate_and_clock)(struct ccid_slot *cs, uint32_t freq_hz, uint32_t rate_bps);
};

/* An instance of CCID (i.e. a card reader device) */
struct ccid_instance {
	/* slots within the reader */
	struct ccid_slot slot[NR_SLOTS];
	/* set of function pointers implementing specific operations */
	const struct ccid_ops *ops;
	const struct ccid_slot_ops *slot_ops;
	/* USB CCID Class Specific Descriptor */
	const struct usb_ccid_class_descriptor *class_desc;
	/* array of permitted data rates; length: bNumDataRatesSupported */
	const uint32_t *data_rates;
	/* array of permitted clock frequencies; length: bNumClockSupported */
	const uint32_t *clock_freqs;
	const char *name;
	/* user-supplied opaque data */
	void *priv;
};

int ccid_slot_send(struct ccid_slot *cs, struct msgb *msg);
int ccid_slot_send_unbusy(struct ccid_slot *cs, struct msgb *msg);
struct msgb *ccid_gen_slot_status(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
				  enum ccid_error_code err);

struct msgb *ccid_gen_data_block(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
				 enum ccid_error_code err, const uint8_t *data,
				 uint32_t data_len);

void ccid_instance_init(struct ccid_instance *ci, const struct ccid_ops *ops,
			const struct ccid_slot_ops *slot_ops,
			const struct usb_ccid_class_descriptor *class_desc,
			const uint32_t *data_rates, const uint32_t *clock_freqs,
			const char *name, void *priv);
int ccid_handle_out(struct ccid_instance *ci, struct msgb *msg);

/* Invalid request received: Please return STALL */
#define CCID_CTRL_RET_INVALID	-1
/* Unknown request received: Not something CCID is supposed to handle */
#define CCID_CTRL_RET_UNKNOWN	0
/* Request OK.  In case of a CTRL-IN: continue by sending wLength bytes to host */
#define CCID_CTRL_RET_OK	1

int ccid_handle_ctrl(struct ccid_instance *ci, const uint8_t *ctrl_req, const uint8_t **data_in);