xref: /openbmc/qemu/hw/usb/dev-smartcard-reader.c (revision 8550a02d)
1f1ae32a1SGerd Hoffmann /*
2f1ae32a1SGerd Hoffmann  * Copyright (C) 2011 Red Hat, Inc.
3f1ae32a1SGerd Hoffmann  *
4f1ae32a1SGerd Hoffmann  * CCID Device emulation
5f1ae32a1SGerd Hoffmann  *
6f1ae32a1SGerd Hoffmann  * Written by Alon Levy, with contributions from Robert Relyea.
7f1ae32a1SGerd Hoffmann  *
8f1ae32a1SGerd Hoffmann  * Based on usb-serial.c, see its copyright and attributions below.
9f1ae32a1SGerd Hoffmann  *
10f1ae32a1SGerd Hoffmann  * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
11f1ae32a1SGerd Hoffmann  * See the COPYING file in the top-level directory.
12f1ae32a1SGerd Hoffmann  * ------- (original copyright & attribution for usb-serial.c below) --------
13f1ae32a1SGerd Hoffmann  * Copyright (c) 2006 CodeSourcery.
14f1ae32a1SGerd Hoffmann  * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
15f1ae32a1SGerd Hoffmann  * Written by Paul Brook, reused for FTDI by Samuel Thibault,
16f1ae32a1SGerd Hoffmann  */
17f1ae32a1SGerd Hoffmann 
18f1ae32a1SGerd Hoffmann /*
19f1ae32a1SGerd Hoffmann  * References:
20f1ae32a1SGerd Hoffmann  *
21f1ae32a1SGerd Hoffmann  * CCID Specification Revision 1.1 April 22nd 2005
22f1ae32a1SGerd Hoffmann  *  "Universal Serial Bus, Device Class: Smart Card"
23f1ae32a1SGerd Hoffmann  *  Specification for Integrated Circuit(s) Cards Interface Devices
24f1ae32a1SGerd Hoffmann  *
25f1ae32a1SGerd Hoffmann  * Endianness note: from the spec (1.3)
26f1ae32a1SGerd Hoffmann  *  "Fields that are larger than a byte are stored in little endian"
27f1ae32a1SGerd Hoffmann  *
28f1ae32a1SGerd Hoffmann  * KNOWN BUGS
29f1ae32a1SGerd Hoffmann  * 1. remove/insert can sometimes result in removed state instead of inserted.
30f1ae32a1SGerd Hoffmann  * This is a result of the following:
31f1ae32a1SGerd Hoffmann  *  symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. This can happen
32f1ae32a1SGerd Hoffmann  *  when a short packet is sent, as seen in uhci-usb.c, resulting from a urb
33f1ae32a1SGerd Hoffmann  *  from the guest requesting SPD and us returning a smaller packet.
34f1ae32a1SGerd Hoffmann  *  Not sure which messages trigger this.
35f1ae32a1SGerd Hoffmann  */
36f1ae32a1SGerd Hoffmann 
37f1ae32a1SGerd Hoffmann #include "qemu-common.h"
381de7afc9SPaolo Bonzini #include "qemu/error-report.h"
39f1ae32a1SGerd Hoffmann #include "hw/usb.h"
40f1ae32a1SGerd Hoffmann #include "hw/usb/desc.h"
4183c9089eSPaolo Bonzini #include "monitor/monitor.h"
42f1ae32a1SGerd Hoffmann 
43f1ae32a1SGerd Hoffmann #include "hw/ccid.h"
44f1ae32a1SGerd Hoffmann 
45f1ae32a1SGerd Hoffmann #define DPRINTF(s, lvl, fmt, ...) \
46f1ae32a1SGerd Hoffmann do { \
47f1ae32a1SGerd Hoffmann     if (lvl <= s->debug) { \
48f1ae32a1SGerd Hoffmann         printf("usb-ccid: " fmt , ## __VA_ARGS__); \
49f1ae32a1SGerd Hoffmann     } \
50f1ae32a1SGerd Hoffmann } while (0)
51f1ae32a1SGerd Hoffmann 
52f1ae32a1SGerd Hoffmann #define D_WARN 1
53f1ae32a1SGerd Hoffmann #define D_INFO 2
54f1ae32a1SGerd Hoffmann #define D_MORE_INFO 3
55f1ae32a1SGerd Hoffmann #define D_VERBOSE 4
56f1ae32a1SGerd Hoffmann 
57f1ae32a1SGerd Hoffmann #define CCID_DEV_NAME "usb-ccid"
58f1ae32a1SGerd Hoffmann 
59f1ae32a1SGerd Hoffmann /*
60f1ae32a1SGerd Hoffmann  * The two options for variable sized buffers:
61f1ae32a1SGerd Hoffmann  * make them constant size, for large enough constant,
62f1ae32a1SGerd Hoffmann  * or handle the migration complexity - VMState doesn't handle this case.
63f1ae32a1SGerd Hoffmann  * sizes are expected never to be exceeded, unless guest misbehaves.
64f1ae32a1SGerd Hoffmann  */
65f1ae32a1SGerd Hoffmann #define BULK_OUT_DATA_SIZE 65536
66f1ae32a1SGerd Hoffmann #define PENDING_ANSWERS_NUM 128
67f1ae32a1SGerd Hoffmann 
68f1ae32a1SGerd Hoffmann #define BULK_IN_BUF_SIZE 384
69f1ae32a1SGerd Hoffmann #define BULK_IN_PENDING_NUM 8
70f1ae32a1SGerd Hoffmann 
71f1ae32a1SGerd Hoffmann #define InterfaceOutClass \
72f1ae32a1SGerd Hoffmann     ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8)
73f1ae32a1SGerd Hoffmann 
74f1ae32a1SGerd Hoffmann #define InterfaceInClass  \
75f1ae32a1SGerd Hoffmann     ((USB_DIR_IN  | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8)
76f1ae32a1SGerd Hoffmann 
77f1ae32a1SGerd Hoffmann #define CCID_MAX_PACKET_SIZE                64
78f1ae32a1SGerd Hoffmann 
79f1ae32a1SGerd Hoffmann #define CCID_CONTROL_ABORT                  0x1
80f1ae32a1SGerd Hoffmann #define CCID_CONTROL_GET_CLOCK_FREQUENCIES  0x2
81f1ae32a1SGerd Hoffmann #define CCID_CONTROL_GET_DATA_RATES         0x3
82f1ae32a1SGerd Hoffmann 
83f1ae32a1SGerd Hoffmann #define CCID_PRODUCT_DESCRIPTION        "QEMU USB CCID"
8493bfef4cSCrístian Viana #define CCID_VENDOR_DESCRIPTION         "QEMU"
85f1ae32a1SGerd Hoffmann #define CCID_INTERFACE_NAME             "CCID Interface"
86f1ae32a1SGerd Hoffmann #define CCID_SERIAL_NUMBER_STRING       "1"
87f1ae32a1SGerd Hoffmann /*
88f1ae32a1SGerd Hoffmann  * Using Gemplus Vendor and Product id
89f1ae32a1SGerd Hoffmann  * Effect on various drivers:
90f1ae32a1SGerd Hoffmann  *  usbccid.sys (winxp, others untested) is a class driver so it doesn't care.
91f1ae32a1SGerd Hoffmann  *  linux has a number of class drivers, but openct filters based on
92f1ae32a1SGerd Hoffmann  *   vendor/product (/etc/openct.conf under fedora), hence Gemplus.
93f1ae32a1SGerd Hoffmann  */
94f1ae32a1SGerd Hoffmann #define CCID_VENDOR_ID                  0x08e6
95f1ae32a1SGerd Hoffmann #define CCID_PRODUCT_ID                 0x4433
96f1ae32a1SGerd Hoffmann #define CCID_DEVICE_VERSION             0x0000
97f1ae32a1SGerd Hoffmann 
98f1ae32a1SGerd Hoffmann /*
99f1ae32a1SGerd Hoffmann  * BULK_OUT messages from PC to Reader
100f1ae32a1SGerd Hoffmann  * Defined in CCID Rev 1.1 6.1 (page 26)
101f1ae32a1SGerd Hoffmann  */
102f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn              0x62
103f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff             0x63
104f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus           0x65
105f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock                0x6f
106f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters           0x6c
107f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters         0x6d
108f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters           0x61
109f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_Escape                  0x6b
110f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock                0x6e
111f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU                  0x6a
112f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_Secure                  0x69
113f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical              0x71
114f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_Abort                   0x72
115f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
116f1ae32a1SGerd Hoffmann 
117f1ae32a1SGerd Hoffmann /*
118f1ae32a1SGerd Hoffmann  * BULK_IN messages from Reader to PC
119f1ae32a1SGerd Hoffmann  * Defined in CCID Rev 1.1 6.2 (page 48)
120f1ae32a1SGerd Hoffmann  */
121f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock               0x80
122f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus              0x81
123f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters              0x82
124f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_Escape                  0x83
125f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
126f1ae32a1SGerd Hoffmann 
127f1ae32a1SGerd Hoffmann /*
128f1ae32a1SGerd Hoffmann  * INTERRUPT_IN messages from Reader to PC
129f1ae32a1SGerd Hoffmann  * Defined in CCID Rev 1.1 6.3 (page 56)
130f1ae32a1SGerd Hoffmann  */
131f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange        0x50
132f1ae32a1SGerd Hoffmann #define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError           0x51
133f1ae32a1SGerd Hoffmann 
134f1ae32a1SGerd Hoffmann /*
135f1ae32a1SGerd Hoffmann  * Endpoints for CCID - addresses are up to us to decide.
136f1ae32a1SGerd Hoffmann  * To support slot insertion and removal we must have an interrupt in ep
137f1ae32a1SGerd Hoffmann  * in addition we need a bulk in and bulk out ep
138f1ae32a1SGerd Hoffmann  * 5.2, page 20
139f1ae32a1SGerd Hoffmann  */
140f1ae32a1SGerd Hoffmann #define CCID_INT_IN_EP       1
141f1ae32a1SGerd Hoffmann #define CCID_BULK_IN_EP      2
142f1ae32a1SGerd Hoffmann #define CCID_BULK_OUT_EP     3
143f1ae32a1SGerd Hoffmann 
144f1ae32a1SGerd Hoffmann /* bmSlotICCState masks */
145f1ae32a1SGerd Hoffmann #define SLOT_0_STATE_MASK    1
146f1ae32a1SGerd Hoffmann #define SLOT_0_CHANGED_MASK  2
147f1ae32a1SGerd Hoffmann 
148f1ae32a1SGerd Hoffmann /* Status codes that go in bStatus (see 6.2.6) */
149f1ae32a1SGerd Hoffmann enum {
150f1ae32a1SGerd Hoffmann     ICC_STATUS_PRESENT_ACTIVE = 0,
151f1ae32a1SGerd Hoffmann     ICC_STATUS_PRESENT_INACTIVE,
152f1ae32a1SGerd Hoffmann     ICC_STATUS_NOT_PRESENT
153f1ae32a1SGerd Hoffmann };
154f1ae32a1SGerd Hoffmann 
155f1ae32a1SGerd Hoffmann enum {
156f1ae32a1SGerd Hoffmann     COMMAND_STATUS_NO_ERROR = 0,
157f1ae32a1SGerd Hoffmann     COMMAND_STATUS_FAILED,
158f1ae32a1SGerd Hoffmann     COMMAND_STATUS_TIME_EXTENSION_REQUIRED
159f1ae32a1SGerd Hoffmann };
160f1ae32a1SGerd Hoffmann 
161f1ae32a1SGerd Hoffmann /* Error codes that go in bError (see 6.2.6) */
162f1ae32a1SGerd Hoffmann enum {
163f1ae32a1SGerd Hoffmann     ERROR_CMD_NOT_SUPPORTED = 0,
164f1ae32a1SGerd Hoffmann     ERROR_CMD_ABORTED       = -1,
165f1ae32a1SGerd Hoffmann     ERROR_ICC_MUTE          = -2,
166f1ae32a1SGerd Hoffmann     ERROR_XFR_PARITY_ERROR  = -3,
167f1ae32a1SGerd Hoffmann     ERROR_XFR_OVERRUN       = -4,
168f1ae32a1SGerd Hoffmann     ERROR_HW_ERROR          = -5,
169f1ae32a1SGerd Hoffmann };
170f1ae32a1SGerd Hoffmann 
171f1ae32a1SGerd Hoffmann /* 6.2.6 RDR_to_PC_SlotStatus definitions */
172f1ae32a1SGerd Hoffmann enum {
173f1ae32a1SGerd Hoffmann     CLOCK_STATUS_RUNNING = 0,
174f1ae32a1SGerd Hoffmann     /*
175f1ae32a1SGerd Hoffmann      * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H,
176f1ae32a1SGerd Hoffmann      * 3 - unknown state. rest are RFU
177f1ae32a1SGerd Hoffmann      */
178f1ae32a1SGerd Hoffmann };
179f1ae32a1SGerd Hoffmann 
180f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_Header {
181f1ae32a1SGerd Hoffmann     uint8_t     bMessageType;
182f1ae32a1SGerd Hoffmann     uint32_t    dwLength;
183f1ae32a1SGerd Hoffmann     uint8_t     bSlot;
184f1ae32a1SGerd Hoffmann     uint8_t     bSeq;
185f1ae32a1SGerd Hoffmann } CCID_Header;
186f1ae32a1SGerd Hoffmann 
187f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_BULK_IN {
188f1ae32a1SGerd Hoffmann     CCID_Header hdr;
189f1ae32a1SGerd Hoffmann     uint8_t     bStatus;        /* Only used in BULK_IN */
190f1ae32a1SGerd Hoffmann     uint8_t     bError;         /* Only used in BULK_IN */
191f1ae32a1SGerd Hoffmann } CCID_BULK_IN;
192f1ae32a1SGerd Hoffmann 
193f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_SlotStatus {
194f1ae32a1SGerd Hoffmann     CCID_BULK_IN b;
195f1ae32a1SGerd Hoffmann     uint8_t     bClockStatus;
196f1ae32a1SGerd Hoffmann } CCID_SlotStatus;
197f1ae32a1SGerd Hoffmann 
198f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_Parameter {
199f1ae32a1SGerd Hoffmann     CCID_BULK_IN b;
200f1ae32a1SGerd Hoffmann     uint8_t     bProtocolNum;
201f1ae32a1SGerd Hoffmann     uint8_t     abProtocolDataStructure[0];
202f1ae32a1SGerd Hoffmann } CCID_Parameter;
203f1ae32a1SGerd Hoffmann 
204f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_DataBlock {
205f1ae32a1SGerd Hoffmann     CCID_BULK_IN b;
206f1ae32a1SGerd Hoffmann     uint8_t      bChainParameter;
207f1ae32a1SGerd Hoffmann     uint8_t      abData[0];
208f1ae32a1SGerd Hoffmann } CCID_DataBlock;
209f1ae32a1SGerd Hoffmann 
210f1ae32a1SGerd Hoffmann /* 6.1.4 PC_to_RDR_XfrBlock */
211f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_XferBlock {
212f1ae32a1SGerd Hoffmann     CCID_Header  hdr;
213f1ae32a1SGerd Hoffmann     uint8_t      bBWI; /* Block Waiting Timeout */
214f1ae32a1SGerd Hoffmann     uint16_t     wLevelParameter; /* XXX currently unused */
215f1ae32a1SGerd Hoffmann     uint8_t      abData[0];
216f1ae32a1SGerd Hoffmann } CCID_XferBlock;
217f1ae32a1SGerd Hoffmann 
218f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_IccPowerOn {
219f1ae32a1SGerd Hoffmann     CCID_Header hdr;
220f1ae32a1SGerd Hoffmann     uint8_t     bPowerSelect;
221f1ae32a1SGerd Hoffmann     uint16_t    abRFU;
222f1ae32a1SGerd Hoffmann } CCID_IccPowerOn;
223f1ae32a1SGerd Hoffmann 
224f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_IccPowerOff {
225f1ae32a1SGerd Hoffmann     CCID_Header hdr;
226f1ae32a1SGerd Hoffmann     uint16_t    abRFU;
227f1ae32a1SGerd Hoffmann } CCID_IccPowerOff;
228f1ae32a1SGerd Hoffmann 
229f1ae32a1SGerd Hoffmann typedef struct QEMU_PACKED CCID_SetParameters {
230f1ae32a1SGerd Hoffmann     CCID_Header hdr;
231f1ae32a1SGerd Hoffmann     uint8_t     bProtocolNum;
232f1ae32a1SGerd Hoffmann     uint16_t   abRFU;
233f1ae32a1SGerd Hoffmann     uint8_t    abProtocolDataStructure[0];
234f1ae32a1SGerd Hoffmann } CCID_SetParameters;
235f1ae32a1SGerd Hoffmann 
236f1ae32a1SGerd Hoffmann typedef struct CCID_Notify_Slot_Change {
237f1ae32a1SGerd Hoffmann     uint8_t     bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */
238f1ae32a1SGerd Hoffmann     uint8_t     bmSlotICCState;
239f1ae32a1SGerd Hoffmann } CCID_Notify_Slot_Change;
240f1ae32a1SGerd Hoffmann 
241f1ae32a1SGerd Hoffmann /* used for DataBlock response to XferBlock */
242f1ae32a1SGerd Hoffmann typedef struct Answer {
243f1ae32a1SGerd Hoffmann     uint8_t slot;
244f1ae32a1SGerd Hoffmann     uint8_t seq;
245f1ae32a1SGerd Hoffmann } Answer;
246f1ae32a1SGerd Hoffmann 
247f1ae32a1SGerd Hoffmann /* pending BULK_IN messages */
248f1ae32a1SGerd Hoffmann typedef struct BulkIn {
249f1ae32a1SGerd Hoffmann     uint8_t  data[BULK_IN_BUF_SIZE];
250f1ae32a1SGerd Hoffmann     uint32_t len;
251f1ae32a1SGerd Hoffmann     uint32_t pos;
252f1ae32a1SGerd Hoffmann } BulkIn;
253f1ae32a1SGerd Hoffmann 
254f1ae32a1SGerd Hoffmann enum {
255f1ae32a1SGerd Hoffmann     MIGRATION_NONE,
256f1ae32a1SGerd Hoffmann     MIGRATION_MIGRATED,
257f1ae32a1SGerd Hoffmann };
258f1ae32a1SGerd Hoffmann 
259f1ae32a1SGerd Hoffmann typedef struct CCIDBus {
260f1ae32a1SGerd Hoffmann     BusState qbus;
261f1ae32a1SGerd Hoffmann } CCIDBus;
262f1ae32a1SGerd Hoffmann 
263f1ae32a1SGerd Hoffmann #define MAX_PROTOCOL_SIZE   7
264f1ae32a1SGerd Hoffmann 
265f1ae32a1SGerd Hoffmann /*
266f1ae32a1SGerd Hoffmann  * powered - defaults to true, changed by PowerOn/PowerOff messages
267f1ae32a1SGerd Hoffmann  */
268f1ae32a1SGerd Hoffmann typedef struct USBCCIDState {
269f1ae32a1SGerd Hoffmann     USBDevice dev;
270f1ae32a1SGerd Hoffmann     USBEndpoint *intr;
271f1ae32a1SGerd Hoffmann     CCIDBus bus;
272f1ae32a1SGerd Hoffmann     CCIDCardState *card;
273f1ae32a1SGerd Hoffmann     BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
274f1ae32a1SGerd Hoffmann     uint32_t bulk_in_pending_start;
275f1ae32a1SGerd Hoffmann     uint32_t bulk_in_pending_end; /* first free */
276f1ae32a1SGerd Hoffmann     uint32_t bulk_in_pending_num;
277f1ae32a1SGerd Hoffmann     BulkIn *current_bulk_in;
278f1ae32a1SGerd Hoffmann     uint8_t  bulk_out_data[BULK_OUT_DATA_SIZE];
279f1ae32a1SGerd Hoffmann     uint32_t bulk_out_pos;
280f1ae32a1SGerd Hoffmann     uint64_t last_answer_error;
281f1ae32a1SGerd Hoffmann     Answer pending_answers[PENDING_ANSWERS_NUM];
282f1ae32a1SGerd Hoffmann     uint32_t pending_answers_start;
283f1ae32a1SGerd Hoffmann     uint32_t pending_answers_end;
284f1ae32a1SGerd Hoffmann     uint32_t pending_answers_num;
285f1ae32a1SGerd Hoffmann     uint8_t  bError;
286f1ae32a1SGerd Hoffmann     uint8_t  bmCommandStatus;
287f1ae32a1SGerd Hoffmann     uint8_t  bProtocolNum;
288f1ae32a1SGerd Hoffmann     uint8_t  abProtocolDataStructure[MAX_PROTOCOL_SIZE];
289f1ae32a1SGerd Hoffmann     uint32_t ulProtocolDataStructureSize;
290f1ae32a1SGerd Hoffmann     uint32_t state_vmstate;
291f1ae32a1SGerd Hoffmann     uint32_t migration_target_ip;
292f1ae32a1SGerd Hoffmann     uint16_t migration_target_port;
293f1ae32a1SGerd Hoffmann     uint8_t  migration_state;
294f1ae32a1SGerd Hoffmann     uint8_t  bmSlotICCState;
295f1ae32a1SGerd Hoffmann     uint8_t  powered;
296f1ae32a1SGerd Hoffmann     uint8_t  notify_slot_change;
297f1ae32a1SGerd Hoffmann     uint8_t  debug;
298f1ae32a1SGerd Hoffmann } USBCCIDState;
299f1ae32a1SGerd Hoffmann 
300f1ae32a1SGerd Hoffmann /*
301f1ae32a1SGerd Hoffmann  * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
302f1ae32a1SGerd Hoffmann  * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
303f1ae32a1SGerd Hoffmann  * Specification.
304f1ae32a1SGerd Hoffmann  *
305f1ae32a1SGerd Hoffmann  * This device implemented based on the spec and with an Athena Smart Card
306f1ae32a1SGerd Hoffmann  * Reader as reference:
307f1ae32a1SGerd Hoffmann  *   0dc3:1004 Athena Smartcard Solutions, Inc.
308f1ae32a1SGerd Hoffmann  */
309f1ae32a1SGerd Hoffmann 
310f1ae32a1SGerd Hoffmann static const uint8_t qemu_ccid_descriptor[] = {
311f1ae32a1SGerd Hoffmann         /* Smart Card Device Class Descriptor */
312f1ae32a1SGerd Hoffmann         0x36,       /* u8  bLength; */
313f1ae32a1SGerd Hoffmann         0x21,       /* u8  bDescriptorType; Functional */
314f1ae32a1SGerd Hoffmann         0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */
315f1ae32a1SGerd Hoffmann         0x00,       /*
316f1ae32a1SGerd Hoffmann                      * u8  bMaxSlotIndex; The index of the highest available
317f1ae32a1SGerd Hoffmann                      * slot on this device. All slots are consecutive starting
318f1ae32a1SGerd Hoffmann                      * at 00h.
319f1ae32a1SGerd Hoffmann                      */
320f1ae32a1SGerd Hoffmann         0x07,       /* u8  bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */
321f1ae32a1SGerd Hoffmann 
322f1ae32a1SGerd Hoffmann         0x03, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/
323f1ae32a1SGerd Hoffmann         0x00, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */
324f1ae32a1SGerd Hoffmann                     /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */
325f1ae32a1SGerd Hoffmann         0xa0, 0x0f, 0x00, 0x00,
326f1ae32a1SGerd Hoffmann                     /* u32 dwMaximumClock; */
327f1ae32a1SGerd Hoffmann         0x00, 0x00, 0x01, 0x00,
328f1ae32a1SGerd Hoffmann         0x00,       /* u8 bNumClockSupported;                 *
329f1ae32a1SGerd Hoffmann                      *    0 means just the default and max.   */
330f1ae32a1SGerd Hoffmann                     /* u32 dwDataRate ;bps. 9600 == 00002580h */
331f1ae32a1SGerd Hoffmann         0x80, 0x25, 0x00, 0x00,
332f1ae32a1SGerd Hoffmann                     /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */
333f1ae32a1SGerd Hoffmann         0x00, 0xC2, 0x01, 0x00,
334f1ae32a1SGerd Hoffmann         0x00,       /* u8  bNumDataRatesSupported; 00 means all rates between
335f1ae32a1SGerd Hoffmann                      *     default and max */
336f1ae32a1SGerd Hoffmann                     /* u32 dwMaxIFSD;                                  *
337f1ae32a1SGerd Hoffmann                      *     maximum IFSD supported by CCID for protocol *
338f1ae32a1SGerd Hoffmann                      *     T=1 (Maximum seen from various cards)       */
339f1ae32a1SGerd Hoffmann         0xfe, 0x00, 0x00, 0x00,
340f1ae32a1SGerd Hoffmann                     /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */
341f1ae32a1SGerd Hoffmann         0x00, 0x00, 0x00, 0x00,
342f1ae32a1SGerd Hoffmann                     /* u32 dwMechanical;  0 - no special characteristics. */
343f1ae32a1SGerd Hoffmann         0x00, 0x00, 0x00, 0x00,
344f1ae32a1SGerd Hoffmann                     /*
345f1ae32a1SGerd Hoffmann                      * u32 dwFeatures;
346f1ae32a1SGerd Hoffmann                      * 0 - No special characteristics
347f1ae32a1SGerd Hoffmann                      * + 2 Automatic parameter configuration based on ATR data
348f1ae32a1SGerd Hoffmann                      * + 4 Automatic activation of ICC on inserting
349f1ae32a1SGerd Hoffmann                      * + 8 Automatic ICC voltage selection
350f1ae32a1SGerd Hoffmann                      * + 10 Automatic ICC clock frequency change
351f1ae32a1SGerd Hoffmann                      * + 20 Automatic baud rate change
352f1ae32a1SGerd Hoffmann                      * + 40 Automatic parameters negotiation made by the CCID
353f1ae32a1SGerd Hoffmann                      * + 80 automatic PPS made by the CCID
354f1ae32a1SGerd Hoffmann                      * 100 CCID can set ICC in clock stop mode
355f1ae32a1SGerd Hoffmann                      * 200 NAD value other then 00 accepted (T=1 protocol)
356f1ae32a1SGerd Hoffmann                      * + 400 Automatic IFSD exchange as first exchange (T=1)
357f1ae32a1SGerd Hoffmann                      * One of the following only:
358f1ae32a1SGerd Hoffmann                      * + 10000 TPDU level exchanges with CCID
359f1ae32a1SGerd Hoffmann                      * 20000 Short APDU level exchange with CCID
360f1ae32a1SGerd Hoffmann                      * 40000 Short and Extended APDU level exchange with CCID
361f1ae32a1SGerd Hoffmann                      *
362f1ae32a1SGerd Hoffmann                      * + 100000 USB Wake up signaling supported on card
363f1ae32a1SGerd Hoffmann                      * insertion and removal. Must set bit 5 in bmAttributes
364f1ae32a1SGerd Hoffmann                      * in Configuration descriptor if 100000 is set.
365f1ae32a1SGerd Hoffmann                      */
366f1ae32a1SGerd Hoffmann         0xfe, 0x04, 0x11, 0x00,
367f1ae32a1SGerd Hoffmann                     /*
368f1ae32a1SGerd Hoffmann                      * u32 dwMaxCCIDMessageLength; For extended APDU in
369f1ae32a1SGerd Hoffmann                      * [261 + 10 , 65544 + 10]. Otherwise the minimum is
370f1ae32a1SGerd Hoffmann                      * wMaxPacketSize of the Bulk-OUT endpoint
371f1ae32a1SGerd Hoffmann                      */
372f1ae32a1SGerd Hoffmann         0x12, 0x00, 0x01, 0x00,
373f1ae32a1SGerd Hoffmann         0xFF,       /*
374f1ae32a1SGerd Hoffmann                      * u8  bClassGetResponse; Significant only for CCID that
375f1ae32a1SGerd Hoffmann                      * offers an APDU level for exchanges. Indicates the
376f1ae32a1SGerd Hoffmann                      * default class value used by the CCID when it sends a
377f1ae32a1SGerd Hoffmann                      * Get Response command to perform the transportation of
378f1ae32a1SGerd Hoffmann                      * an APDU by T=0 protocol
379f1ae32a1SGerd Hoffmann                      * FFh indicates that the CCID echos the class of the APDU.
380f1ae32a1SGerd Hoffmann                      */
381f1ae32a1SGerd Hoffmann         0xFF,       /*
382f1ae32a1SGerd Hoffmann                      * u8  bClassEnvelope; EAPDU only. Envelope command for
383f1ae32a1SGerd Hoffmann                      * T=0
384f1ae32a1SGerd Hoffmann                      */
385f1ae32a1SGerd Hoffmann         0x00, 0x00, /*
386f1ae32a1SGerd Hoffmann                      * u16 wLcdLayout; XXYY Number of lines (XX) and chars per
387f1ae32a1SGerd Hoffmann                      * line for LCD display used for PIN entry. 0000 - no LCD
388f1ae32a1SGerd Hoffmann                      */
389f1ae32a1SGerd Hoffmann         0x01,       /*
390f1ae32a1SGerd Hoffmann                      * u8  bPINSupport; 01h PIN Verification,
391f1ae32a1SGerd Hoffmann                      *                  02h PIN Modification
392f1ae32a1SGerd Hoffmann                      */
393f1ae32a1SGerd Hoffmann         0x01,       /* u8  bMaxCCIDBusySlots; */
394f1ae32a1SGerd Hoffmann };
395f1ae32a1SGerd Hoffmann 
396f1ae32a1SGerd Hoffmann enum {
397f1ae32a1SGerd Hoffmann     STR_MANUFACTURER = 1,
398f1ae32a1SGerd Hoffmann     STR_PRODUCT,
399f1ae32a1SGerd Hoffmann     STR_SERIALNUMBER,
400f1ae32a1SGerd Hoffmann     STR_INTERFACE,
401f1ae32a1SGerd Hoffmann };
402f1ae32a1SGerd Hoffmann 
403f1ae32a1SGerd Hoffmann static const USBDescStrings desc_strings = {
40493bfef4cSCrístian Viana     [STR_MANUFACTURER]  = "QEMU",
405f1ae32a1SGerd Hoffmann     [STR_PRODUCT]       = "QEMU USB CCID",
406f1ae32a1SGerd Hoffmann     [STR_SERIALNUMBER]  = "1",
407f1ae32a1SGerd Hoffmann     [STR_INTERFACE]     = "CCID Interface",
408f1ae32a1SGerd Hoffmann };
409f1ae32a1SGerd Hoffmann 
410f1ae32a1SGerd Hoffmann static const USBDescIface desc_iface0 = {
411f1ae32a1SGerd Hoffmann     .bInterfaceNumber              = 0,
412f1ae32a1SGerd Hoffmann     .bNumEndpoints                 = 3,
413f1ae32a1SGerd Hoffmann     .bInterfaceClass               = 0x0b,
414f1ae32a1SGerd Hoffmann     .bInterfaceSubClass            = 0x00,
415f1ae32a1SGerd Hoffmann     .bInterfaceProtocol            = 0x00,
416f1ae32a1SGerd Hoffmann     .iInterface                    = STR_INTERFACE,
417f1ae32a1SGerd Hoffmann     .ndesc                         = 1,
418f1ae32a1SGerd Hoffmann     .descs = (USBDescOther[]) {
419f1ae32a1SGerd Hoffmann         {
420f1ae32a1SGerd Hoffmann             /* smartcard descriptor */
421f1ae32a1SGerd Hoffmann             .data = qemu_ccid_descriptor,
422f1ae32a1SGerd Hoffmann         },
423f1ae32a1SGerd Hoffmann     },
424f1ae32a1SGerd Hoffmann     .eps = (USBDescEndpoint[]) {
425f1ae32a1SGerd Hoffmann         {
426f1ae32a1SGerd Hoffmann             .bEndpointAddress      = USB_DIR_IN | CCID_INT_IN_EP,
427f1ae32a1SGerd Hoffmann             .bmAttributes          = USB_ENDPOINT_XFER_INT,
428f1ae32a1SGerd Hoffmann             .bInterval             = 255,
429f1ae32a1SGerd Hoffmann             .wMaxPacketSize        = 64,
430f1ae32a1SGerd Hoffmann         },{
431f1ae32a1SGerd Hoffmann             .bEndpointAddress      = USB_DIR_IN | CCID_BULK_IN_EP,
432f1ae32a1SGerd Hoffmann             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
433f1ae32a1SGerd Hoffmann             .wMaxPacketSize        = 64,
434f1ae32a1SGerd Hoffmann         },{
435f1ae32a1SGerd Hoffmann             .bEndpointAddress      = USB_DIR_OUT | CCID_BULK_OUT_EP,
436f1ae32a1SGerd Hoffmann             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
437f1ae32a1SGerd Hoffmann             .wMaxPacketSize        = 64,
438f1ae32a1SGerd Hoffmann         },
439f1ae32a1SGerd Hoffmann     }
440f1ae32a1SGerd Hoffmann };
441f1ae32a1SGerd Hoffmann 
442f1ae32a1SGerd Hoffmann static const USBDescDevice desc_device = {
443f1ae32a1SGerd Hoffmann     .bcdUSB                        = 0x0110,
444f1ae32a1SGerd Hoffmann     .bMaxPacketSize0               = 64,
445f1ae32a1SGerd Hoffmann     .bNumConfigurations            = 1,
446f1ae32a1SGerd Hoffmann     .confs = (USBDescConfig[]) {
447f1ae32a1SGerd Hoffmann         {
448f1ae32a1SGerd Hoffmann             .bNumInterfaces        = 1,
449f1ae32a1SGerd Hoffmann             .bConfigurationValue   = 1,
450f1ae32a1SGerd Hoffmann             .bmAttributes          = 0xe0,
451f1ae32a1SGerd Hoffmann             .bMaxPower             = 50,
452f1ae32a1SGerd Hoffmann             .nif = 1,
453f1ae32a1SGerd Hoffmann             .ifs = &desc_iface0,
454f1ae32a1SGerd Hoffmann         },
455f1ae32a1SGerd Hoffmann     },
456f1ae32a1SGerd Hoffmann };
457f1ae32a1SGerd Hoffmann 
458f1ae32a1SGerd Hoffmann static const USBDesc desc_ccid = {
459f1ae32a1SGerd Hoffmann     .id = {
460f1ae32a1SGerd Hoffmann         .idVendor          = CCID_VENDOR_ID,
461f1ae32a1SGerd Hoffmann         .idProduct         = CCID_PRODUCT_ID,
462f1ae32a1SGerd Hoffmann         .bcdDevice         = CCID_DEVICE_VERSION,
463f1ae32a1SGerd Hoffmann         .iManufacturer     = STR_MANUFACTURER,
464f1ae32a1SGerd Hoffmann         .iProduct          = STR_PRODUCT,
465f1ae32a1SGerd Hoffmann         .iSerialNumber     = STR_SERIALNUMBER,
466f1ae32a1SGerd Hoffmann     },
467f1ae32a1SGerd Hoffmann     .full = &desc_device,
468f1ae32a1SGerd Hoffmann     .str  = desc_strings,
469f1ae32a1SGerd Hoffmann };
470f1ae32a1SGerd Hoffmann 
471f1ae32a1SGerd Hoffmann static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
472f1ae32a1SGerd Hoffmann {
473f1ae32a1SGerd Hoffmann     CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
474f1ae32a1SGerd Hoffmann     if (cc->get_atr) {
475f1ae32a1SGerd Hoffmann         return cc->get_atr(card, len);
476f1ae32a1SGerd Hoffmann     }
477f1ae32a1SGerd Hoffmann     return NULL;
478f1ae32a1SGerd Hoffmann }
479f1ae32a1SGerd Hoffmann 
480f1ae32a1SGerd Hoffmann static void ccid_card_apdu_from_guest(CCIDCardState *card,
481f1ae32a1SGerd Hoffmann                                       const uint8_t *apdu,
482f1ae32a1SGerd Hoffmann                                       uint32_t len)
483f1ae32a1SGerd Hoffmann {
484f1ae32a1SGerd Hoffmann     CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
485f1ae32a1SGerd Hoffmann     if (cc->apdu_from_guest) {
486f1ae32a1SGerd Hoffmann         cc->apdu_from_guest(card, apdu, len);
487f1ae32a1SGerd Hoffmann     }
488f1ae32a1SGerd Hoffmann }
489f1ae32a1SGerd Hoffmann 
490f1ae32a1SGerd Hoffmann static int ccid_card_exitfn(CCIDCardState *card)
491f1ae32a1SGerd Hoffmann {
492f1ae32a1SGerd Hoffmann     CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
493f1ae32a1SGerd Hoffmann     if (cc->exitfn) {
494f1ae32a1SGerd Hoffmann         return cc->exitfn(card);
495f1ae32a1SGerd Hoffmann     }
496f1ae32a1SGerd Hoffmann     return 0;
497f1ae32a1SGerd Hoffmann }
498f1ae32a1SGerd Hoffmann 
499f1ae32a1SGerd Hoffmann static int ccid_card_initfn(CCIDCardState *card)
500f1ae32a1SGerd Hoffmann {
501f1ae32a1SGerd Hoffmann     CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
502f1ae32a1SGerd Hoffmann     if (cc->initfn) {
503f1ae32a1SGerd Hoffmann         return cc->initfn(card);
504f1ae32a1SGerd Hoffmann     }
505f1ae32a1SGerd Hoffmann     return 0;
506f1ae32a1SGerd Hoffmann }
507f1ae32a1SGerd Hoffmann 
508f1ae32a1SGerd Hoffmann static bool ccid_has_pending_answers(USBCCIDState *s)
509f1ae32a1SGerd Hoffmann {
510f1ae32a1SGerd Hoffmann     return s->pending_answers_num > 0;
511f1ae32a1SGerd Hoffmann }
512f1ae32a1SGerd Hoffmann 
513f1ae32a1SGerd Hoffmann static void ccid_clear_pending_answers(USBCCIDState *s)
514f1ae32a1SGerd Hoffmann {
515f1ae32a1SGerd Hoffmann     s->pending_answers_num = 0;
516f1ae32a1SGerd Hoffmann     s->pending_answers_start = 0;
517f1ae32a1SGerd Hoffmann     s->pending_answers_end = 0;
518f1ae32a1SGerd Hoffmann }
519f1ae32a1SGerd Hoffmann 
520f1ae32a1SGerd Hoffmann static void ccid_print_pending_answers(USBCCIDState *s)
521f1ae32a1SGerd Hoffmann {
522f1ae32a1SGerd Hoffmann     Answer *answer;
523f1ae32a1SGerd Hoffmann     int i, count;
524f1ae32a1SGerd Hoffmann 
525f1ae32a1SGerd Hoffmann     DPRINTF(s, D_VERBOSE, "usb-ccid: pending answers:");
526f1ae32a1SGerd Hoffmann     if (!ccid_has_pending_answers(s)) {
527f1ae32a1SGerd Hoffmann         DPRINTF(s, D_VERBOSE, " empty\n");
528f1ae32a1SGerd Hoffmann         return;
529f1ae32a1SGerd Hoffmann     }
530f1ae32a1SGerd Hoffmann     for (i = s->pending_answers_start, count = s->pending_answers_num ;
531f1ae32a1SGerd Hoffmann          count > 0; count--, i++) {
532f1ae32a1SGerd Hoffmann         answer = &s->pending_answers[i % PENDING_ANSWERS_NUM];
533f1ae32a1SGerd Hoffmann         if (count == 1) {
534f1ae32a1SGerd Hoffmann             DPRINTF(s, D_VERBOSE, "%d:%d\n", answer->slot, answer->seq);
535f1ae32a1SGerd Hoffmann         } else {
536f1ae32a1SGerd Hoffmann             DPRINTF(s, D_VERBOSE, "%d:%d,", answer->slot, answer->seq);
537f1ae32a1SGerd Hoffmann         }
538f1ae32a1SGerd Hoffmann     }
539f1ae32a1SGerd Hoffmann }
540f1ae32a1SGerd Hoffmann 
541f1ae32a1SGerd Hoffmann static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr)
542f1ae32a1SGerd Hoffmann {
543f1ae32a1SGerd Hoffmann     Answer *answer;
544f1ae32a1SGerd Hoffmann 
545f1ae32a1SGerd Hoffmann     assert(s->pending_answers_num < PENDING_ANSWERS_NUM);
546f1ae32a1SGerd Hoffmann     s->pending_answers_num++;
547f1ae32a1SGerd Hoffmann     answer =
548f1ae32a1SGerd Hoffmann         &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM];
549f1ae32a1SGerd Hoffmann     answer->slot = hdr->bSlot;
550f1ae32a1SGerd Hoffmann     answer->seq = hdr->bSeq;
551f1ae32a1SGerd Hoffmann     ccid_print_pending_answers(s);
552f1ae32a1SGerd Hoffmann }
553f1ae32a1SGerd Hoffmann 
554f1ae32a1SGerd Hoffmann static void ccid_remove_pending_answer(USBCCIDState *s,
555f1ae32a1SGerd Hoffmann     uint8_t *slot, uint8_t *seq)
556f1ae32a1SGerd Hoffmann {
557f1ae32a1SGerd Hoffmann     Answer *answer;
558f1ae32a1SGerd Hoffmann 
559f1ae32a1SGerd Hoffmann     assert(s->pending_answers_num > 0);
560f1ae32a1SGerd Hoffmann     s->pending_answers_num--;
561f1ae32a1SGerd Hoffmann     answer =
562f1ae32a1SGerd Hoffmann         &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM];
563f1ae32a1SGerd Hoffmann     *slot = answer->slot;
564f1ae32a1SGerd Hoffmann     *seq = answer->seq;
565f1ae32a1SGerd Hoffmann     ccid_print_pending_answers(s);
566f1ae32a1SGerd Hoffmann }
567f1ae32a1SGerd Hoffmann 
568f1ae32a1SGerd Hoffmann static void ccid_bulk_in_clear(USBCCIDState *s)
569f1ae32a1SGerd Hoffmann {
570f1ae32a1SGerd Hoffmann     s->bulk_in_pending_start = 0;
571f1ae32a1SGerd Hoffmann     s->bulk_in_pending_end = 0;
572f1ae32a1SGerd Hoffmann     s->bulk_in_pending_num = 0;
573f1ae32a1SGerd Hoffmann }
574f1ae32a1SGerd Hoffmann 
575f1ae32a1SGerd Hoffmann static void ccid_bulk_in_release(USBCCIDState *s)
576f1ae32a1SGerd Hoffmann {
577f1ae32a1SGerd Hoffmann     assert(s->current_bulk_in != NULL);
578f1ae32a1SGerd Hoffmann     s->current_bulk_in->pos = 0;
579f1ae32a1SGerd Hoffmann     s->current_bulk_in = NULL;
580f1ae32a1SGerd Hoffmann }
581f1ae32a1SGerd Hoffmann 
582f1ae32a1SGerd Hoffmann static void ccid_bulk_in_get(USBCCIDState *s)
583f1ae32a1SGerd Hoffmann {
584f1ae32a1SGerd Hoffmann     if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) {
585f1ae32a1SGerd Hoffmann         return;
586f1ae32a1SGerd Hoffmann     }
587f1ae32a1SGerd Hoffmann     assert(s->bulk_in_pending_num > 0);
588f1ae32a1SGerd Hoffmann     s->bulk_in_pending_num--;
589f1ae32a1SGerd Hoffmann     s->current_bulk_in =
590f1ae32a1SGerd Hoffmann         &s->bulk_in_pending[(s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM];
591f1ae32a1SGerd Hoffmann }
592f1ae32a1SGerd Hoffmann 
593f1ae32a1SGerd Hoffmann static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len)
594f1ae32a1SGerd Hoffmann {
595f1ae32a1SGerd Hoffmann     BulkIn *bulk_in;
596f1ae32a1SGerd Hoffmann 
597f1ae32a1SGerd Hoffmann     DPRINTF(s, D_VERBOSE, "%s: QUEUE: reserve %d bytes\n", __func__, len);
598f1ae32a1SGerd Hoffmann 
599f1ae32a1SGerd Hoffmann     /* look for an existing element */
600f1ae32a1SGerd Hoffmann     if (len > BULK_IN_BUF_SIZE) {
601f1ae32a1SGerd Hoffmann         DPRINTF(s, D_WARN, "usb-ccid.c: %s: len larger then max (%d>%d). "
602f1ae32a1SGerd Hoffmann                            "discarding message.\n",
603f1ae32a1SGerd Hoffmann                            __func__, len, BULK_IN_BUF_SIZE);
604f1ae32a1SGerd Hoffmann         return NULL;
605f1ae32a1SGerd Hoffmann     }
606f1ae32a1SGerd Hoffmann     if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) {
607f1ae32a1SGerd Hoffmann         DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. "
608f1ae32a1SGerd Hoffmann                            "discarding message.\n", __func__);
609f1ae32a1SGerd Hoffmann         return NULL;
610f1ae32a1SGerd Hoffmann     }
611f1ae32a1SGerd Hoffmann     bulk_in =
612f1ae32a1SGerd Hoffmann         &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM];
613f1ae32a1SGerd Hoffmann     s->bulk_in_pending_num++;
614f1ae32a1SGerd Hoffmann     bulk_in->len = len;
615f1ae32a1SGerd Hoffmann     return bulk_in->data;
616f1ae32a1SGerd Hoffmann }
617f1ae32a1SGerd Hoffmann 
618f1ae32a1SGerd Hoffmann static void ccid_reset(USBCCIDState *s)
619f1ae32a1SGerd Hoffmann {
620f1ae32a1SGerd Hoffmann     ccid_bulk_in_clear(s);
621f1ae32a1SGerd Hoffmann     ccid_clear_pending_answers(s);
622f1ae32a1SGerd Hoffmann }
623f1ae32a1SGerd Hoffmann 
624f1ae32a1SGerd Hoffmann static void ccid_detach(USBCCIDState *s)
625f1ae32a1SGerd Hoffmann {
626f1ae32a1SGerd Hoffmann     ccid_reset(s);
627f1ae32a1SGerd Hoffmann }
628f1ae32a1SGerd Hoffmann 
629f1ae32a1SGerd Hoffmann static void ccid_handle_reset(USBDevice *dev)
630f1ae32a1SGerd Hoffmann {
631f1ae32a1SGerd Hoffmann     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
632f1ae32a1SGerd Hoffmann 
633f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "Reset\n");
634f1ae32a1SGerd Hoffmann 
635f1ae32a1SGerd Hoffmann     ccid_reset(s);
636f1ae32a1SGerd Hoffmann }
637f1ae32a1SGerd Hoffmann 
6389a77a0f5SHans de Goede static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
639f1ae32a1SGerd Hoffmann                                int value, int index, int length, uint8_t *data)
640f1ae32a1SGerd Hoffmann {
641f1ae32a1SGerd Hoffmann     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
6429a77a0f5SHans de Goede     int ret;
643f1ae32a1SGerd Hoffmann 
644f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "got control %x, value %x\n", request, value);
645f1ae32a1SGerd Hoffmann     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
646f1ae32a1SGerd Hoffmann     if (ret >= 0) {
6479a77a0f5SHans de Goede         return;
648f1ae32a1SGerd Hoffmann     }
649f1ae32a1SGerd Hoffmann 
650f1ae32a1SGerd Hoffmann     switch (request) {
651f1ae32a1SGerd Hoffmann         /* Class specific requests.  */
652f1ae32a1SGerd Hoffmann     case InterfaceOutClass | CCID_CONTROL_ABORT:
653f1ae32a1SGerd Hoffmann         DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
6549a77a0f5SHans de Goede         p->status = USB_RET_STALL;
655f1ae32a1SGerd Hoffmann         break;
656f1ae32a1SGerd Hoffmann     case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
657f1ae32a1SGerd Hoffmann         DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
6589a77a0f5SHans de Goede         p->status = USB_RET_STALL;
659f1ae32a1SGerd Hoffmann         break;
660f1ae32a1SGerd Hoffmann     case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES:
661f1ae32a1SGerd Hoffmann         DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
6629a77a0f5SHans de Goede         p->status = USB_RET_STALL;
663f1ae32a1SGerd Hoffmann         break;
664f1ae32a1SGerd Hoffmann     default:
665f1ae32a1SGerd Hoffmann         DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
666f1ae32a1SGerd Hoffmann                 request, value);
6679a77a0f5SHans de Goede         p->status = USB_RET_STALL;
668f1ae32a1SGerd Hoffmann         break;
669f1ae32a1SGerd Hoffmann     }
670f1ae32a1SGerd Hoffmann }
671f1ae32a1SGerd Hoffmann 
672f1ae32a1SGerd Hoffmann static bool ccid_card_inserted(USBCCIDState *s)
673f1ae32a1SGerd Hoffmann {
674f1ae32a1SGerd Hoffmann     return s->bmSlotICCState & SLOT_0_STATE_MASK;
675f1ae32a1SGerd Hoffmann }
676f1ae32a1SGerd Hoffmann 
677f1ae32a1SGerd Hoffmann static uint8_t ccid_card_status(USBCCIDState *s)
678f1ae32a1SGerd Hoffmann {
679f1ae32a1SGerd Hoffmann     return ccid_card_inserted(s)
680f1ae32a1SGerd Hoffmann             ? (s->powered ?
681f1ae32a1SGerd Hoffmann                 ICC_STATUS_PRESENT_ACTIVE
682f1ae32a1SGerd Hoffmann               : ICC_STATUS_PRESENT_INACTIVE
683f1ae32a1SGerd Hoffmann               )
684f1ae32a1SGerd Hoffmann             : ICC_STATUS_NOT_PRESENT;
685f1ae32a1SGerd Hoffmann }
686f1ae32a1SGerd Hoffmann 
687f1ae32a1SGerd Hoffmann static uint8_t ccid_calc_status(USBCCIDState *s)
688f1ae32a1SGerd Hoffmann {
689f1ae32a1SGerd Hoffmann     /*
690f1ae32a1SGerd Hoffmann      * page 55, 6.2.6, calculation of bStatus from bmICCStatus and
691f1ae32a1SGerd Hoffmann      * bmCommandStatus
692f1ae32a1SGerd Hoffmann      */
693f1ae32a1SGerd Hoffmann     uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6);
694f1ae32a1SGerd Hoffmann     DPRINTF(s, D_VERBOSE, "status = %d\n", ret);
695f1ae32a1SGerd Hoffmann     return ret;
696f1ae32a1SGerd Hoffmann }
697f1ae32a1SGerd Hoffmann 
698f1ae32a1SGerd Hoffmann static void ccid_reset_error_status(USBCCIDState *s)
699f1ae32a1SGerd Hoffmann {
700f1ae32a1SGerd Hoffmann     s->bError = ERROR_CMD_NOT_SUPPORTED;
701f1ae32a1SGerd Hoffmann     s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
702f1ae32a1SGerd Hoffmann }
703f1ae32a1SGerd Hoffmann 
704f1ae32a1SGerd Hoffmann static void ccid_write_slot_status(USBCCIDState *s, CCID_Header *recv)
705f1ae32a1SGerd Hoffmann {
706f1ae32a1SGerd Hoffmann     CCID_SlotStatus *h = ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus));
707f1ae32a1SGerd Hoffmann     if (h == NULL) {
708f1ae32a1SGerd Hoffmann         return;
709f1ae32a1SGerd Hoffmann     }
710f1ae32a1SGerd Hoffmann     h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus;
711f1ae32a1SGerd Hoffmann     h->b.hdr.dwLength = 0;
712f1ae32a1SGerd Hoffmann     h->b.hdr.bSlot = recv->bSlot;
713f1ae32a1SGerd Hoffmann     h->b.hdr.bSeq = recv->bSeq;
714f1ae32a1SGerd Hoffmann     h->b.bStatus = ccid_calc_status(s);
715f1ae32a1SGerd Hoffmann     h->b.bError = s->bError;
716f1ae32a1SGerd Hoffmann     h->bClockStatus = CLOCK_STATUS_RUNNING;
717f1ae32a1SGerd Hoffmann     ccid_reset_error_status(s);
718f1ae32a1SGerd Hoffmann }
719f1ae32a1SGerd Hoffmann 
720f1ae32a1SGerd Hoffmann static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv)
721f1ae32a1SGerd Hoffmann {
722f1ae32a1SGerd Hoffmann     CCID_Parameter *h;
723f1ae32a1SGerd Hoffmann     uint32_t len = s->ulProtocolDataStructureSize;
724f1ae32a1SGerd Hoffmann 
725f1ae32a1SGerd Hoffmann     h = ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len);
726f1ae32a1SGerd Hoffmann     if (h == NULL) {
727f1ae32a1SGerd Hoffmann         return;
728f1ae32a1SGerd Hoffmann     }
729f1ae32a1SGerd Hoffmann     h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters;
730f1ae32a1SGerd Hoffmann     h->b.hdr.dwLength = 0;
731f1ae32a1SGerd Hoffmann     h->b.hdr.bSlot = recv->bSlot;
732f1ae32a1SGerd Hoffmann     h->b.hdr.bSeq = recv->bSeq;
733f1ae32a1SGerd Hoffmann     h->b.bStatus = ccid_calc_status(s);
734f1ae32a1SGerd Hoffmann     h->b.bError = s->bError;
735f1ae32a1SGerd Hoffmann     h->bProtocolNum = s->bProtocolNum;
736f1ae32a1SGerd Hoffmann     memcpy(h->abProtocolDataStructure, s->abProtocolDataStructure, len);
737f1ae32a1SGerd Hoffmann     ccid_reset_error_status(s);
738f1ae32a1SGerd Hoffmann }
739f1ae32a1SGerd Hoffmann 
740f1ae32a1SGerd Hoffmann static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq,
741f1ae32a1SGerd Hoffmann                                   const uint8_t *data, uint32_t len)
742f1ae32a1SGerd Hoffmann {
743f1ae32a1SGerd Hoffmann     CCID_DataBlock *p = ccid_reserve_recv_buf(s, sizeof(*p) + len);
744f1ae32a1SGerd Hoffmann 
745f1ae32a1SGerd Hoffmann     if (p == NULL) {
746f1ae32a1SGerd Hoffmann         return;
747f1ae32a1SGerd Hoffmann     }
748f1ae32a1SGerd Hoffmann     p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock;
749f1ae32a1SGerd Hoffmann     p->b.hdr.dwLength = cpu_to_le32(len);
750f1ae32a1SGerd Hoffmann     p->b.hdr.bSlot = slot;
751f1ae32a1SGerd Hoffmann     p->b.hdr.bSeq = seq;
752f1ae32a1SGerd Hoffmann     p->b.bStatus = ccid_calc_status(s);
753f1ae32a1SGerd Hoffmann     p->b.bError = s->bError;
754f1ae32a1SGerd Hoffmann     if (p->b.bError) {
755f1ae32a1SGerd Hoffmann         DPRINTF(s, D_VERBOSE, "error %d", p->b.bError);
756f1ae32a1SGerd Hoffmann     }
757f1ae32a1SGerd Hoffmann     memcpy(p->abData, data, len);
758f1ae32a1SGerd Hoffmann     ccid_reset_error_status(s);
759f1ae32a1SGerd Hoffmann }
760f1ae32a1SGerd Hoffmann 
761f1ae32a1SGerd Hoffmann static void ccid_write_data_block_answer(USBCCIDState *s,
762f1ae32a1SGerd Hoffmann     const uint8_t *data, uint32_t len)
763f1ae32a1SGerd Hoffmann {
764f1ae32a1SGerd Hoffmann     uint8_t seq;
765f1ae32a1SGerd Hoffmann     uint8_t slot;
766f1ae32a1SGerd Hoffmann 
767f1ae32a1SGerd Hoffmann     if (!ccid_has_pending_answers(s)) {
768f1ae32a1SGerd Hoffmann         abort();
769f1ae32a1SGerd Hoffmann     }
770f1ae32a1SGerd Hoffmann     ccid_remove_pending_answer(s, &slot, &seq);
771f1ae32a1SGerd Hoffmann     ccid_write_data_block(s, slot, seq, data, len);
772f1ae32a1SGerd Hoffmann }
773f1ae32a1SGerd Hoffmann 
774f1ae32a1SGerd Hoffmann static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
775f1ae32a1SGerd Hoffmann {
776f1ae32a1SGerd Hoffmann     const uint8_t *atr = NULL;
777f1ae32a1SGerd Hoffmann     uint32_t len = 0;
778f1ae32a1SGerd Hoffmann 
779f1ae32a1SGerd Hoffmann     if (s->card) {
780f1ae32a1SGerd Hoffmann         atr = ccid_card_get_atr(s->card, &len);
781f1ae32a1SGerd Hoffmann     }
782f1ae32a1SGerd Hoffmann     ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
783f1ae32a1SGerd Hoffmann }
784f1ae32a1SGerd Hoffmann 
785f1ae32a1SGerd Hoffmann static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv)
786f1ae32a1SGerd Hoffmann {
787f1ae32a1SGerd Hoffmann     CCID_SetParameters *ph = (CCID_SetParameters *) recv;
788f1ae32a1SGerd Hoffmann     uint32_t len = 0;
789f1ae32a1SGerd Hoffmann     if ((ph->bProtocolNum & 3) == 0) {
790f1ae32a1SGerd Hoffmann         len = 5;
791f1ae32a1SGerd Hoffmann     }
792f1ae32a1SGerd Hoffmann     if ((ph->bProtocolNum & 3) == 1) {
793f1ae32a1SGerd Hoffmann         len = 7;
794f1ae32a1SGerd Hoffmann     }
795f1ae32a1SGerd Hoffmann     if (len == 0) {
796f1ae32a1SGerd Hoffmann         s->bmCommandStatus = COMMAND_STATUS_FAILED;
797f1ae32a1SGerd Hoffmann         s->bError = 7; /* Protocol invalid or not supported */
798f1ae32a1SGerd Hoffmann         return;
799f1ae32a1SGerd Hoffmann     }
800f1ae32a1SGerd Hoffmann     s->bProtocolNum = ph->bProtocolNum;
801f1ae32a1SGerd Hoffmann     memcpy(s->abProtocolDataStructure, ph->abProtocolDataStructure, len);
802f1ae32a1SGerd Hoffmann     s->ulProtocolDataStructureSize = len;
803f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "%s: using len %d\n", __func__, len);
804f1ae32a1SGerd Hoffmann }
805f1ae32a1SGerd Hoffmann 
806f1ae32a1SGerd Hoffmann /*
807f1ae32a1SGerd Hoffmann  * must be 5 bytes for T=0, 7 bytes for T=1
808f1ae32a1SGerd Hoffmann  * See page 52
809f1ae32a1SGerd Hoffmann  */
810f1ae32a1SGerd Hoffmann static const uint8_t abDefaultProtocolDataStructure[7] = {
811f1ae32a1SGerd Hoffmann     0x77, 0x00, 0x00, 0x00, 0x00, 0xfe /*IFSC*/, 0x00 /*NAD*/ };
812f1ae32a1SGerd Hoffmann 
813f1ae32a1SGerd Hoffmann static void ccid_reset_parameters(USBCCIDState *s)
814f1ae32a1SGerd Hoffmann {
815f1ae32a1SGerd Hoffmann    uint32_t len = sizeof(abDefaultProtocolDataStructure);
816f1ae32a1SGerd Hoffmann 
817f1ae32a1SGerd Hoffmann    s->bProtocolNum = 1; /* T=1 */
818f1ae32a1SGerd Hoffmann    s->ulProtocolDataStructureSize = len;
819f1ae32a1SGerd Hoffmann    memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len);
820f1ae32a1SGerd Hoffmann }
821f1ae32a1SGerd Hoffmann 
822f1ae32a1SGerd Hoffmann static void ccid_report_error_failed(USBCCIDState *s, uint8_t error)
823f1ae32a1SGerd Hoffmann {
824f1ae32a1SGerd Hoffmann     s->bmCommandStatus = COMMAND_STATUS_FAILED;
825f1ae32a1SGerd Hoffmann     s->bError = error;
826f1ae32a1SGerd Hoffmann }
827f1ae32a1SGerd Hoffmann 
828f1ae32a1SGerd Hoffmann /* NOTE: only a single slot is supported (SLOT_0) */
829f1ae32a1SGerd Hoffmann static void ccid_on_slot_change(USBCCIDState *s, bool full)
830f1ae32a1SGerd Hoffmann {
831f1ae32a1SGerd Hoffmann     /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 */
832f1ae32a1SGerd Hoffmann     uint8_t current = s->bmSlotICCState;
833f1ae32a1SGerd Hoffmann     if (full) {
834f1ae32a1SGerd Hoffmann         s->bmSlotICCState |= SLOT_0_STATE_MASK;
835f1ae32a1SGerd Hoffmann     } else {
836f1ae32a1SGerd Hoffmann         s->bmSlotICCState &= ~SLOT_0_STATE_MASK;
837f1ae32a1SGerd Hoffmann     }
838f1ae32a1SGerd Hoffmann     if (current != s->bmSlotICCState) {
839f1ae32a1SGerd Hoffmann         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
840f1ae32a1SGerd Hoffmann     }
841f1ae32a1SGerd Hoffmann     s->notify_slot_change = true;
842*8550a02dSGerd Hoffmann     usb_wakeup(s->intr, 0);
843f1ae32a1SGerd Hoffmann }
844f1ae32a1SGerd Hoffmann 
845f1ae32a1SGerd Hoffmann static void ccid_write_data_block_error(
846f1ae32a1SGerd Hoffmann     USBCCIDState *s, uint8_t slot, uint8_t seq)
847f1ae32a1SGerd Hoffmann {
848f1ae32a1SGerd Hoffmann     ccid_write_data_block(s, slot, seq, NULL, 0);
849f1ae32a1SGerd Hoffmann }
850f1ae32a1SGerd Hoffmann 
851f1ae32a1SGerd Hoffmann static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
852f1ae32a1SGerd Hoffmann {
853f1ae32a1SGerd Hoffmann     uint32_t len;
854f1ae32a1SGerd Hoffmann 
855f1ae32a1SGerd Hoffmann     if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) {
856f1ae32a1SGerd Hoffmann         DPRINTF(s, 1,
857f1ae32a1SGerd Hoffmann                 "usb-ccid: not sending apdu to client, no card connected\n");
858f1ae32a1SGerd Hoffmann         ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
859f1ae32a1SGerd Hoffmann         return;
860f1ae32a1SGerd Hoffmann     }
861f1ae32a1SGerd Hoffmann     len = le32_to_cpu(recv->hdr.dwLength);
862f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__,
863f1ae32a1SGerd Hoffmann                 recv->hdr.bSeq, len);
864f1ae32a1SGerd Hoffmann     ccid_add_pending_answer(s, (CCID_Header *)recv);
865f1ae32a1SGerd Hoffmann     if (s->card) {
866f1ae32a1SGerd Hoffmann         ccid_card_apdu_from_guest(s->card, recv->abData, len);
867f1ae32a1SGerd Hoffmann     } else {
868f1ae32a1SGerd Hoffmann         DPRINTF(s, D_WARN, "warning: discarded apdu\n");
869f1ae32a1SGerd Hoffmann     }
870f1ae32a1SGerd Hoffmann }
871f1ae32a1SGerd Hoffmann 
8729a77a0f5SHans de Goede static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
873f1ae32a1SGerd Hoffmann {
874f1ae32a1SGerd Hoffmann     CCID_Header *ccid_header;
875f1ae32a1SGerd Hoffmann 
876f1ae32a1SGerd Hoffmann     if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
8779a77a0f5SHans de Goede         p->status = USB_RET_STALL;
8789a77a0f5SHans de Goede         return;
879f1ae32a1SGerd Hoffmann     }
880f1ae32a1SGerd Hoffmann     ccid_header = (CCID_Header *)s->bulk_out_data;
881f1ae32a1SGerd Hoffmann     usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
882f1ae32a1SGerd Hoffmann     s->bulk_out_pos += p->iov.size;
883f1ae32a1SGerd Hoffmann     if (p->iov.size == CCID_MAX_PACKET_SIZE) {
884f1ae32a1SGerd Hoffmann         DPRINTF(s, D_VERBOSE,
885f1ae32a1SGerd Hoffmann             "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
886f1ae32a1SGerd Hoffmann             p->iov.size, ccid_header->dwLength);
8879a77a0f5SHans de Goede         return;
888f1ae32a1SGerd Hoffmann     }
889f1ae32a1SGerd Hoffmann     if (s->bulk_out_pos < 10) {
890f1ae32a1SGerd Hoffmann         DPRINTF(s, 1,
891f1ae32a1SGerd Hoffmann                 "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
892f1ae32a1SGerd Hoffmann                 __func__);
893f1ae32a1SGerd Hoffmann     } else {
894f1ae32a1SGerd Hoffmann         DPRINTF(s, D_MORE_INFO, "%s %x\n", __func__, ccid_header->bMessageType);
895f1ae32a1SGerd Hoffmann         switch (ccid_header->bMessageType) {
896f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
897f1ae32a1SGerd Hoffmann             ccid_write_slot_status(s, ccid_header);
898f1ae32a1SGerd Hoffmann             break;
899f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
900f1ae32a1SGerd Hoffmann             DPRINTF(s, 1, "PowerOn: %d\n",
901f1ae32a1SGerd Hoffmann                 ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect);
902f1ae32a1SGerd Hoffmann             s->powered = true;
903f1ae32a1SGerd Hoffmann             if (!ccid_card_inserted(s)) {
904f1ae32a1SGerd Hoffmann                 ccid_report_error_failed(s, ERROR_ICC_MUTE);
905f1ae32a1SGerd Hoffmann             }
906f1ae32a1SGerd Hoffmann             /* atr is written regardless of error. */
907f1ae32a1SGerd Hoffmann             ccid_write_data_block_atr(s, ccid_header);
908f1ae32a1SGerd Hoffmann             break;
909f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
910f1ae32a1SGerd Hoffmann             DPRINTF(s, 1, "PowerOff\n");
911f1ae32a1SGerd Hoffmann             ccid_reset_error_status(s);
912f1ae32a1SGerd Hoffmann             s->powered = false;
913f1ae32a1SGerd Hoffmann             ccid_write_slot_status(s, ccid_header);
914f1ae32a1SGerd Hoffmann             break;
915f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
916f1ae32a1SGerd Hoffmann             ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
917f1ae32a1SGerd Hoffmann             break;
918f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
919f1ae32a1SGerd Hoffmann             ccid_reset_error_status(s);
920f1ae32a1SGerd Hoffmann             ccid_set_parameters(s, ccid_header);
921f1ae32a1SGerd Hoffmann             ccid_write_parameters(s, ccid_header);
922f1ae32a1SGerd Hoffmann             break;
923f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
924f1ae32a1SGerd Hoffmann             ccid_reset_error_status(s);
925f1ae32a1SGerd Hoffmann             ccid_reset_parameters(s);
926f1ae32a1SGerd Hoffmann             ccid_write_parameters(s, ccid_header);
927f1ae32a1SGerd Hoffmann             break;
928f1ae32a1SGerd Hoffmann         case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
929f1ae32a1SGerd Hoffmann             ccid_reset_error_status(s);
930f1ae32a1SGerd Hoffmann             ccid_write_parameters(s, ccid_header);
931f1ae32a1SGerd Hoffmann             break;
932f1ae32a1SGerd Hoffmann         default:
933f1ae32a1SGerd Hoffmann             DPRINTF(s, 1,
934f1ae32a1SGerd Hoffmann                 "handle_data: ERROR: unhandled message type %Xh\n",
935f1ae32a1SGerd Hoffmann                 ccid_header->bMessageType);
936f1ae32a1SGerd Hoffmann             /*
937f1ae32a1SGerd Hoffmann              * The caller is expecting the device to respond, tell it we
938f1ae32a1SGerd Hoffmann              * don't support the operation.
939f1ae32a1SGerd Hoffmann              */
940f1ae32a1SGerd Hoffmann             ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
941f1ae32a1SGerd Hoffmann             ccid_write_slot_status(s, ccid_header);
942f1ae32a1SGerd Hoffmann             break;
943f1ae32a1SGerd Hoffmann         }
944f1ae32a1SGerd Hoffmann     }
945f1ae32a1SGerd Hoffmann     s->bulk_out_pos = 0;
946f1ae32a1SGerd Hoffmann }
947f1ae32a1SGerd Hoffmann 
9489a77a0f5SHans de Goede static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
949f1ae32a1SGerd Hoffmann {
9509a77a0f5SHans de Goede     int len = 0;
951f1ae32a1SGerd Hoffmann 
952f1ae32a1SGerd Hoffmann     ccid_bulk_in_get(s);
953f1ae32a1SGerd Hoffmann     if (s->current_bulk_in != NULL) {
9549a77a0f5SHans de Goede         len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
955f1ae32a1SGerd Hoffmann                   p->iov.size);
956f1ae32a1SGerd Hoffmann         usb_packet_copy(p, s->current_bulk_in->data +
9579a77a0f5SHans de Goede                         s->current_bulk_in->pos, len);
9589a77a0f5SHans de Goede         s->current_bulk_in->pos += len;
959f1ae32a1SGerd Hoffmann         if (s->current_bulk_in->pos == s->current_bulk_in->len) {
960f1ae32a1SGerd Hoffmann             ccid_bulk_in_release(s);
961f1ae32a1SGerd Hoffmann         }
962f1ae32a1SGerd Hoffmann     } else {
963f1ae32a1SGerd Hoffmann         /* return when device has no data - usb 2.0 spec Table 8-4 */
9649a77a0f5SHans de Goede         p->status = USB_RET_NAK;
965f1ae32a1SGerd Hoffmann     }
9669a77a0f5SHans de Goede     if (len) {
967f1ae32a1SGerd Hoffmann         DPRINTF(s, D_MORE_INFO,
968f1ae32a1SGerd Hoffmann                 "%s: %zd/%d req/act to guest (BULK_IN)\n",
9699a77a0f5SHans de Goede                 __func__, p->iov.size, len);
970f1ae32a1SGerd Hoffmann     }
9719a77a0f5SHans de Goede     if (len < p->iov.size) {
972f1ae32a1SGerd Hoffmann         DPRINTF(s, 1,
973f1ae32a1SGerd Hoffmann                 "%s: returning short (EREMOTEIO) %d < %zd\n",
9749a77a0f5SHans de Goede                 __func__, len, p->iov.size);
975f1ae32a1SGerd Hoffmann     }
976f1ae32a1SGerd Hoffmann }
977f1ae32a1SGerd Hoffmann 
9789a77a0f5SHans de Goede static void ccid_handle_data(USBDevice *dev, USBPacket *p)
979f1ae32a1SGerd Hoffmann {
980f1ae32a1SGerd Hoffmann     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
981f1ae32a1SGerd Hoffmann     uint8_t buf[2];
982f1ae32a1SGerd Hoffmann 
983f1ae32a1SGerd Hoffmann     switch (p->pid) {
984f1ae32a1SGerd Hoffmann     case USB_TOKEN_OUT:
9859a77a0f5SHans de Goede         ccid_handle_bulk_out(s, p);
986f1ae32a1SGerd Hoffmann         break;
987f1ae32a1SGerd Hoffmann 
988f1ae32a1SGerd Hoffmann     case USB_TOKEN_IN:
989f1ae32a1SGerd Hoffmann         switch (p->ep->nr) {
990f1ae32a1SGerd Hoffmann         case CCID_BULK_IN_EP:
9919a77a0f5SHans de Goede             ccid_bulk_in_copy_to_guest(s, p);
992f1ae32a1SGerd Hoffmann             break;
993f1ae32a1SGerd Hoffmann         case CCID_INT_IN_EP:
994f1ae32a1SGerd Hoffmann             if (s->notify_slot_change) {
995f1ae32a1SGerd Hoffmann                 /* page 56, RDR_to_PC_NotifySlotChange */
996f1ae32a1SGerd Hoffmann                 buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
997f1ae32a1SGerd Hoffmann                 buf[1] = s->bmSlotICCState;
998f1ae32a1SGerd Hoffmann                 usb_packet_copy(p, buf, 2);
999f1ae32a1SGerd Hoffmann                 s->notify_slot_change = false;
1000f1ae32a1SGerd Hoffmann                 s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
1001f1ae32a1SGerd Hoffmann                 DPRINTF(s, D_INFO,
1002f1ae32a1SGerd Hoffmann                         "handle_data: int_in: notify_slot_change %X, "
1003f1ae32a1SGerd Hoffmann                         "requested len %zd\n",
1004f1ae32a1SGerd Hoffmann                         s->bmSlotICCState, p->iov.size);
1005c4020746SHans de Goede             } else {
1006c4020746SHans de Goede                 p->status = USB_RET_NAK;
1007f1ae32a1SGerd Hoffmann             }
1008f1ae32a1SGerd Hoffmann             break;
1009f1ae32a1SGerd Hoffmann         default:
1010f1ae32a1SGerd Hoffmann             DPRINTF(s, 1, "Bad endpoint\n");
10119a77a0f5SHans de Goede             p->status = USB_RET_STALL;
1012f1ae32a1SGerd Hoffmann             break;
1013f1ae32a1SGerd Hoffmann         }
1014f1ae32a1SGerd Hoffmann         break;
1015f1ae32a1SGerd Hoffmann     default:
1016f1ae32a1SGerd Hoffmann         DPRINTF(s, 1, "Bad token\n");
10179a77a0f5SHans de Goede         p->status = USB_RET_STALL;
1018f1ae32a1SGerd Hoffmann         break;
1019f1ae32a1SGerd Hoffmann     }
1020f1ae32a1SGerd Hoffmann }
1021f1ae32a1SGerd Hoffmann 
1022f1ae32a1SGerd Hoffmann static void ccid_handle_destroy(USBDevice *dev)
1023f1ae32a1SGerd Hoffmann {
1024f1ae32a1SGerd Hoffmann     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
1025f1ae32a1SGerd Hoffmann 
1026f1ae32a1SGerd Hoffmann     ccid_bulk_in_clear(s);
1027f1ae32a1SGerd Hoffmann }
1028f1ae32a1SGerd Hoffmann 
1029f1ae32a1SGerd Hoffmann static void ccid_flush_pending_answers(USBCCIDState *s)
1030f1ae32a1SGerd Hoffmann {
1031f1ae32a1SGerd Hoffmann     while (ccid_has_pending_answers(s)) {
1032f1ae32a1SGerd Hoffmann         ccid_write_data_block_answer(s, NULL, 0);
1033f1ae32a1SGerd Hoffmann     }
1034f1ae32a1SGerd Hoffmann }
1035f1ae32a1SGerd Hoffmann 
1036f1ae32a1SGerd Hoffmann static Answer *ccid_peek_next_answer(USBCCIDState *s)
1037f1ae32a1SGerd Hoffmann {
1038f1ae32a1SGerd Hoffmann     return s->pending_answers_num == 0
1039f1ae32a1SGerd Hoffmann         ? NULL
1040f1ae32a1SGerd Hoffmann         : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
1041f1ae32a1SGerd Hoffmann }
1042f1ae32a1SGerd Hoffmann 
10433cb75a7cSPaolo Bonzini static Property ccid_props[] = {
10443cb75a7cSPaolo Bonzini     DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
10453cb75a7cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
10463cb75a7cSPaolo Bonzini };
10473cb75a7cSPaolo Bonzini 
10480d936928SAnthony Liguori #define TYPE_CCID_BUS "ccid-bus"
10490d936928SAnthony Liguori #define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS)
10500d936928SAnthony Liguori 
10510d936928SAnthony Liguori static const TypeInfo ccid_bus_info = {
10520d936928SAnthony Liguori     .name = TYPE_CCID_BUS,
10530d936928SAnthony Liguori     .parent = TYPE_BUS,
10540d936928SAnthony Liguori     .instance_size = sizeof(CCIDBus),
1055f1ae32a1SGerd Hoffmann };
1056f1ae32a1SGerd Hoffmann 
1057f1ae32a1SGerd Hoffmann void ccid_card_send_apdu_to_guest(CCIDCardState *card,
1058f1ae32a1SGerd Hoffmann                                   uint8_t *apdu, uint32_t len)
1059f1ae32a1SGerd Hoffmann {
1060f1ae32a1SGerd Hoffmann     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev.qdev,
1061f1ae32a1SGerd Hoffmann                                 card->qdev.parent_bus->parent);
1062f1ae32a1SGerd Hoffmann     Answer *answer;
1063f1ae32a1SGerd Hoffmann 
1064f1ae32a1SGerd Hoffmann     if (!ccid_has_pending_answers(s)) {
1065f1ae32a1SGerd Hoffmann         DPRINTF(s, 1, "CCID ERROR: got an APDU without pending answers\n");
1066f1ae32a1SGerd Hoffmann         return;
1067f1ae32a1SGerd Hoffmann     }
1068f1ae32a1SGerd Hoffmann     s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
1069f1ae32a1SGerd Hoffmann     answer = ccid_peek_next_answer(s);
1070f1ae32a1SGerd Hoffmann     if (answer == NULL) {
1071f1ae32a1SGerd Hoffmann         abort();
1072f1ae32a1SGerd Hoffmann     }
1073f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n",
1074f1ae32a1SGerd Hoffmann         len, answer->seq, answer->slot);
1075f1ae32a1SGerd Hoffmann     ccid_write_data_block_answer(s, apdu, len);
1076f1ae32a1SGerd Hoffmann }
1077f1ae32a1SGerd Hoffmann 
1078f1ae32a1SGerd Hoffmann void ccid_card_card_removed(CCIDCardState *card)
1079f1ae32a1SGerd Hoffmann {
1080f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1081f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1082f1ae32a1SGerd Hoffmann 
1083f1ae32a1SGerd Hoffmann     ccid_on_slot_change(s, false);
1084f1ae32a1SGerd Hoffmann     ccid_flush_pending_answers(s);
1085f1ae32a1SGerd Hoffmann     ccid_reset(s);
1086f1ae32a1SGerd Hoffmann }
1087f1ae32a1SGerd Hoffmann 
1088f1ae32a1SGerd Hoffmann int ccid_card_ccid_attach(CCIDCardState *card)
1089f1ae32a1SGerd Hoffmann {
1090f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1091f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1092f1ae32a1SGerd Hoffmann 
1093f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "CCID Attach\n");
1094f1ae32a1SGerd Hoffmann     if (s->migration_state == MIGRATION_MIGRATED) {
1095f1ae32a1SGerd Hoffmann         s->migration_state = MIGRATION_NONE;
1096f1ae32a1SGerd Hoffmann     }
1097f1ae32a1SGerd Hoffmann     return 0;
1098f1ae32a1SGerd Hoffmann }
1099f1ae32a1SGerd Hoffmann 
1100f1ae32a1SGerd Hoffmann void ccid_card_ccid_detach(CCIDCardState *card)
1101f1ae32a1SGerd Hoffmann {
1102f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1103f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1104f1ae32a1SGerd Hoffmann 
1105f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "CCID Detach\n");
1106f1ae32a1SGerd Hoffmann     if (ccid_card_inserted(s)) {
1107f1ae32a1SGerd Hoffmann         ccid_on_slot_change(s, false);
1108f1ae32a1SGerd Hoffmann     }
1109f1ae32a1SGerd Hoffmann     ccid_detach(s);
1110f1ae32a1SGerd Hoffmann }
1111f1ae32a1SGerd Hoffmann 
1112f1ae32a1SGerd Hoffmann void ccid_card_card_error(CCIDCardState *card, uint64_t error)
1113f1ae32a1SGerd Hoffmann {
1114f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1115f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1116f1ae32a1SGerd Hoffmann 
1117f1ae32a1SGerd Hoffmann     s->bmCommandStatus = COMMAND_STATUS_FAILED;
1118f1ae32a1SGerd Hoffmann     s->last_answer_error = error;
1119f1ae32a1SGerd Hoffmann     DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error);
1120f1ae32a1SGerd Hoffmann     /* TODO: these errors should be more verbose and propagated to the guest.*/
1121f1ae32a1SGerd Hoffmann     /*
1122f1ae32a1SGerd Hoffmann      * We flush all pending answers on CardRemove message in ccid-card-passthru,
1123f1ae32a1SGerd Hoffmann      * so check that first to not trigger abort
1124f1ae32a1SGerd Hoffmann      */
1125f1ae32a1SGerd Hoffmann     if (ccid_has_pending_answers(s)) {
1126f1ae32a1SGerd Hoffmann         ccid_write_data_block_answer(s, NULL, 0);
1127f1ae32a1SGerd Hoffmann     }
1128f1ae32a1SGerd Hoffmann }
1129f1ae32a1SGerd Hoffmann 
1130f1ae32a1SGerd Hoffmann void ccid_card_card_inserted(CCIDCardState *card)
1131f1ae32a1SGerd Hoffmann {
1132f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1133f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1134f1ae32a1SGerd Hoffmann 
1135f1ae32a1SGerd Hoffmann     s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
1136f1ae32a1SGerd Hoffmann     ccid_flush_pending_answers(s);
1137f1ae32a1SGerd Hoffmann     ccid_on_slot_change(s, true);
1138f1ae32a1SGerd Hoffmann }
1139f1ae32a1SGerd Hoffmann 
1140f1ae32a1SGerd Hoffmann static int ccid_card_exit(DeviceState *qdev)
1141f1ae32a1SGerd Hoffmann {
1142f1ae32a1SGerd Hoffmann     int ret = 0;
1143f1ae32a1SGerd Hoffmann     CCIDCardState *card = CCID_CARD(qdev);
1144f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1145f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1146f1ae32a1SGerd Hoffmann 
1147f1ae32a1SGerd Hoffmann     if (ccid_card_inserted(s)) {
1148f1ae32a1SGerd Hoffmann         ccid_card_card_removed(card);
1149f1ae32a1SGerd Hoffmann     }
1150f1ae32a1SGerd Hoffmann     ret = ccid_card_exitfn(card);
1151f1ae32a1SGerd Hoffmann     s->card = NULL;
1152f1ae32a1SGerd Hoffmann     return ret;
1153f1ae32a1SGerd Hoffmann }
1154f1ae32a1SGerd Hoffmann 
1155f1ae32a1SGerd Hoffmann static int ccid_card_init(DeviceState *qdev)
1156f1ae32a1SGerd Hoffmann {
1157f1ae32a1SGerd Hoffmann     CCIDCardState *card = CCID_CARD(qdev);
1158f1ae32a1SGerd Hoffmann     USBCCIDState *s =
1159f1ae32a1SGerd Hoffmann         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
1160f1ae32a1SGerd Hoffmann     int ret = 0;
1161f1ae32a1SGerd Hoffmann 
1162f1ae32a1SGerd Hoffmann     if (card->slot != 0) {
1163f1ae32a1SGerd Hoffmann         error_report("Warning: usb-ccid supports one slot, can't add %d",
1164f1ae32a1SGerd Hoffmann                 card->slot);
1165f1ae32a1SGerd Hoffmann         return -1;
1166f1ae32a1SGerd Hoffmann     }
1167f1ae32a1SGerd Hoffmann     if (s->card != NULL) {
1168f1ae32a1SGerd Hoffmann         error_report("Warning: usb-ccid card already full, not adding");
1169f1ae32a1SGerd Hoffmann         return -1;
1170f1ae32a1SGerd Hoffmann     }
1171f1ae32a1SGerd Hoffmann     ret = ccid_card_initfn(card);
1172f1ae32a1SGerd Hoffmann     if (ret == 0) {
1173f1ae32a1SGerd Hoffmann         s->card = card;
1174f1ae32a1SGerd Hoffmann     }
1175f1ae32a1SGerd Hoffmann     return ret;
1176f1ae32a1SGerd Hoffmann }
1177f1ae32a1SGerd Hoffmann 
1178f1ae32a1SGerd Hoffmann static int ccid_initfn(USBDevice *dev)
1179f1ae32a1SGerd Hoffmann {
1180f1ae32a1SGerd Hoffmann     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
1181f1ae32a1SGerd Hoffmann 
11829d55d1adSGerd Hoffmann     usb_desc_create_serial(dev);
1183f1ae32a1SGerd Hoffmann     usb_desc_init(dev);
11840d936928SAnthony Liguori     qbus_create_inplace(&s->bus.qbus, TYPE_CCID_BUS, &dev->qdev, NULL);
1185f1ae32a1SGerd Hoffmann     s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
1186f1ae32a1SGerd Hoffmann     s->bus.qbus.allow_hotplug = 1;
1187f1ae32a1SGerd Hoffmann     s->card = NULL;
1188f1ae32a1SGerd Hoffmann     s->migration_state = MIGRATION_NONE;
1189f1ae32a1SGerd Hoffmann     s->migration_target_ip = 0;
1190f1ae32a1SGerd Hoffmann     s->migration_target_port = 0;
1191f1ae32a1SGerd Hoffmann     s->dev.speed = USB_SPEED_FULL;
1192f1ae32a1SGerd Hoffmann     s->dev.speedmask = USB_SPEED_MASK_FULL;
1193f1ae32a1SGerd Hoffmann     s->notify_slot_change = false;
1194f1ae32a1SGerd Hoffmann     s->powered = true;
1195f1ae32a1SGerd Hoffmann     s->pending_answers_num = 0;
1196f1ae32a1SGerd Hoffmann     s->last_answer_error = 0;
1197f1ae32a1SGerd Hoffmann     s->bulk_in_pending_start = 0;
1198f1ae32a1SGerd Hoffmann     s->bulk_in_pending_end = 0;
1199f1ae32a1SGerd Hoffmann     s->current_bulk_in = NULL;
1200f1ae32a1SGerd Hoffmann     ccid_reset_error_status(s);
1201f1ae32a1SGerd Hoffmann     s->bulk_out_pos = 0;
1202f1ae32a1SGerd Hoffmann     ccid_reset_parameters(s);
1203f1ae32a1SGerd Hoffmann     ccid_reset(s);
1204f1ae32a1SGerd Hoffmann     return 0;
1205f1ae32a1SGerd Hoffmann }
1206f1ae32a1SGerd Hoffmann 
1207f1ae32a1SGerd Hoffmann static int ccid_post_load(void *opaque, int version_id)
1208f1ae32a1SGerd Hoffmann {
1209f1ae32a1SGerd Hoffmann     USBCCIDState *s = opaque;
1210f1ae32a1SGerd Hoffmann 
1211f1ae32a1SGerd Hoffmann     /*
1212f1ae32a1SGerd Hoffmann      * This must be done after usb_device_attach, which sets state to ATTACHED,
1213f1ae32a1SGerd Hoffmann      * while it must be DEFAULT in order to accept packets (like it is after
1214f1ae32a1SGerd Hoffmann      * reset, but reset will reset our addr and call our reset handler which
1215f1ae32a1SGerd Hoffmann      * may change state, and we don't want to do that when migrating).
1216f1ae32a1SGerd Hoffmann      */
1217f1ae32a1SGerd Hoffmann     s->dev.state = s->state_vmstate;
1218f1ae32a1SGerd Hoffmann     return 0;
1219f1ae32a1SGerd Hoffmann }
1220f1ae32a1SGerd Hoffmann 
1221f1ae32a1SGerd Hoffmann static void ccid_pre_save(void *opaque)
1222f1ae32a1SGerd Hoffmann {
1223f1ae32a1SGerd Hoffmann     USBCCIDState *s = opaque;
1224f1ae32a1SGerd Hoffmann 
1225f1ae32a1SGerd Hoffmann     s->state_vmstate = s->dev.state;
1226f1ae32a1SGerd Hoffmann     if (s->dev.attached) {
1227f1ae32a1SGerd Hoffmann         /*
1228f1ae32a1SGerd Hoffmann          * Migrating an open device, ignore reconnection CHR_EVENT to avoid an
1229f1ae32a1SGerd Hoffmann          * erroneous detach.
1230f1ae32a1SGerd Hoffmann          */
1231f1ae32a1SGerd Hoffmann         s->migration_state = MIGRATION_MIGRATED;
1232f1ae32a1SGerd Hoffmann     }
1233f1ae32a1SGerd Hoffmann }
1234f1ae32a1SGerd Hoffmann 
1235f1ae32a1SGerd Hoffmann static VMStateDescription bulk_in_vmstate = {
1236f1ae32a1SGerd Hoffmann     .name = "CCID BulkIn state",
1237f1ae32a1SGerd Hoffmann     .version_id = 1,
1238f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
1239f1ae32a1SGerd Hoffmann     .fields = (VMStateField[]) {
1240f1ae32a1SGerd Hoffmann         VMSTATE_BUFFER(data, BulkIn),
1241f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(len, BulkIn),
1242f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(pos, BulkIn),
1243f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST()
1244f1ae32a1SGerd Hoffmann     }
1245f1ae32a1SGerd Hoffmann };
1246f1ae32a1SGerd Hoffmann 
1247f1ae32a1SGerd Hoffmann static VMStateDescription answer_vmstate = {
1248f1ae32a1SGerd Hoffmann     .name = "CCID Answer state",
1249f1ae32a1SGerd Hoffmann     .version_id = 1,
1250f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
1251f1ae32a1SGerd Hoffmann     .fields = (VMStateField[]) {
1252f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(slot, Answer),
1253f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(seq, Answer),
1254f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST()
1255f1ae32a1SGerd Hoffmann     }
1256f1ae32a1SGerd Hoffmann };
1257f1ae32a1SGerd Hoffmann 
1258f1ae32a1SGerd Hoffmann static VMStateDescription usb_device_vmstate = {
1259f1ae32a1SGerd Hoffmann     .name = "usb_device",
1260f1ae32a1SGerd Hoffmann     .version_id = 1,
1261f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
1262f1ae32a1SGerd Hoffmann     .fields = (VMStateField[]) {
1263f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(addr, USBDevice),
1264f1ae32a1SGerd Hoffmann         VMSTATE_BUFFER(setup_buf, USBDevice),
1265f1ae32a1SGerd Hoffmann         VMSTATE_BUFFER(data_buf, USBDevice),
1266f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST()
1267f1ae32a1SGerd Hoffmann     }
1268f1ae32a1SGerd Hoffmann };
1269f1ae32a1SGerd Hoffmann 
1270f1ae32a1SGerd Hoffmann static VMStateDescription ccid_vmstate = {
1271f1ae32a1SGerd Hoffmann     .name = CCID_DEV_NAME,
1272f1ae32a1SGerd Hoffmann     .version_id = 1,
1273f1ae32a1SGerd Hoffmann     .minimum_version_id = 1,
1274f1ae32a1SGerd Hoffmann     .post_load = ccid_post_load,
1275f1ae32a1SGerd Hoffmann     .pre_save = ccid_pre_save,
1276f1ae32a1SGerd Hoffmann     .fields = (VMStateField[]) {
1277f1ae32a1SGerd Hoffmann         VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice),
1278f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(debug, USBCCIDState),
1279f1ae32a1SGerd Hoffmann         VMSTATE_BUFFER(bulk_out_data, USBCCIDState),
1280f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(bulk_out_pos, USBCCIDState),
1281f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(bmSlotICCState, USBCCIDState),
1282f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(powered, USBCCIDState),
1283f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(notify_slot_change, USBCCIDState),
1284f1ae32a1SGerd Hoffmann         VMSTATE_UINT64(last_answer_error, USBCCIDState),
1285f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(bError, USBCCIDState),
1286f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(bmCommandStatus, USBCCIDState),
1287f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(bProtocolNum, USBCCIDState),
1288f1ae32a1SGerd Hoffmann         VMSTATE_BUFFER(abProtocolDataStructure, USBCCIDState),
1289f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState),
1290f1ae32a1SGerd Hoffmann         VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState,
1291f1ae32a1SGerd Hoffmann                        BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn),
1292f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState),
1293f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState),
1294f1ae32a1SGerd Hoffmann         VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState,
1295f1ae32a1SGerd Hoffmann                         PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer),
1296f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(pending_answers_num, USBCCIDState),
1297f1ae32a1SGerd Hoffmann         VMSTATE_UINT8(migration_state, USBCCIDState),
1298f1ae32a1SGerd Hoffmann         VMSTATE_UINT32(state_vmstate, USBCCIDState),
1299f1ae32a1SGerd Hoffmann         VMSTATE_END_OF_LIST()
1300f1ae32a1SGerd Hoffmann     }
1301f1ae32a1SGerd Hoffmann };
1302f1ae32a1SGerd Hoffmann 
1303f1ae32a1SGerd Hoffmann static Property ccid_properties[] = {
1304f1ae32a1SGerd Hoffmann     DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
1305f1ae32a1SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
1306f1ae32a1SGerd Hoffmann };
1307f1ae32a1SGerd Hoffmann 
1308f1ae32a1SGerd Hoffmann static void ccid_class_initfn(ObjectClass *klass, void *data)
1309f1ae32a1SGerd Hoffmann {
1310f1ae32a1SGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
1311f1ae32a1SGerd Hoffmann     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
1312f1ae32a1SGerd Hoffmann 
1313f1ae32a1SGerd Hoffmann     uc->init           = ccid_initfn;
1314f1ae32a1SGerd Hoffmann     uc->product_desc   = "QEMU USB CCID";
1315f1ae32a1SGerd Hoffmann     uc->usb_desc       = &desc_ccid;
1316f1ae32a1SGerd Hoffmann     uc->handle_reset   = ccid_handle_reset;
1317f1ae32a1SGerd Hoffmann     uc->handle_control = ccid_handle_control;
1318f1ae32a1SGerd Hoffmann     uc->handle_data    = ccid_handle_data;
1319f1ae32a1SGerd Hoffmann     uc->handle_destroy = ccid_handle_destroy;
1320f1ae32a1SGerd Hoffmann     dc->desc = "CCID Rev 1.1 smartcard reader";
1321f1ae32a1SGerd Hoffmann     dc->vmsd = &ccid_vmstate;
1322f1ae32a1SGerd Hoffmann     dc->props = ccid_properties;
1323f1ae32a1SGerd Hoffmann }
1324f1ae32a1SGerd Hoffmann 
13258c43a6f0SAndreas Färber static const TypeInfo ccid_info = {
1326f1ae32a1SGerd Hoffmann     .name          = CCID_DEV_NAME,
1327f1ae32a1SGerd Hoffmann     .parent        = TYPE_USB_DEVICE,
1328f1ae32a1SGerd Hoffmann     .instance_size = sizeof(USBCCIDState),
1329f1ae32a1SGerd Hoffmann     .class_init    = ccid_class_initfn,
1330f1ae32a1SGerd Hoffmann };
1331f1ae32a1SGerd Hoffmann 
1332f1ae32a1SGerd Hoffmann static void ccid_card_class_init(ObjectClass *klass, void *data)
1333f1ae32a1SGerd Hoffmann {
1334f1ae32a1SGerd Hoffmann     DeviceClass *k = DEVICE_CLASS(klass);
13350d936928SAnthony Liguori     k->bus_type = TYPE_CCID_BUS;
1336f1ae32a1SGerd Hoffmann     k->init = ccid_card_init;
1337f1ae32a1SGerd Hoffmann     k->exit = ccid_card_exit;
1338bce54474SPaolo Bonzini     k->props = ccid_props;
1339f1ae32a1SGerd Hoffmann }
1340f1ae32a1SGerd Hoffmann 
13418c43a6f0SAndreas Färber static const TypeInfo ccid_card_type_info = {
1342f1ae32a1SGerd Hoffmann     .name = TYPE_CCID_CARD,
1343f1ae32a1SGerd Hoffmann     .parent = TYPE_DEVICE,
1344f1ae32a1SGerd Hoffmann     .instance_size = sizeof(CCIDCardState),
1345f1ae32a1SGerd Hoffmann     .abstract = true,
1346f1ae32a1SGerd Hoffmann     .class_size = sizeof(CCIDCardClass),
1347f1ae32a1SGerd Hoffmann     .class_init = ccid_card_class_init,
1348f1ae32a1SGerd Hoffmann };
1349f1ae32a1SGerd Hoffmann 
1350f1ae32a1SGerd Hoffmann static void ccid_register_types(void)
1351f1ae32a1SGerd Hoffmann {
13520d936928SAnthony Liguori     type_register_static(&ccid_bus_info);
1353f1ae32a1SGerd Hoffmann     type_register_static(&ccid_card_type_info);
1354f1ae32a1SGerd Hoffmann     type_register_static(&ccid_info);
1355f1ae32a1SGerd Hoffmann     usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
1356f1ae32a1SGerd Hoffmann }
1357f1ae32a1SGerd Hoffmann 
1358f1ae32a1SGerd Hoffmann type_init(ccid_register_types)
1359