summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2010-08-15 17:44:02 +0300
committerAlon Levy <alevy@redhat.com>2010-08-15 17:53:19 +0300
commit2b78d3c47f3ab391326a432da4b781c02f8316bd (patch)
tree2fa04bb3ca27c50e6ac4a51bafb05ad2101bdc27
parent208a85702c3bc598f72291a4a5953e6d56e7e560 (diff)
usb-ccid: some beautification, updated protocolspice.kvm.v14.usb_ccid_original_patches
-rw-r--r--hw/usb-ccid.c286
-rw-r--r--vscard_common.h118
2 files changed, 292 insertions, 112 deletions
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 1fd028cb7..2d50f9444 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1,19 +1,29 @@
/*
* CCID Device emulation
*
+ * Based on usb-serial.c:
* Copyright (c) 2006 CodeSourcery.
* Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
- * Copyright (c) 2010 Red Hat.
* Written by Paul Brook, reused for FTDI by Samuel Thibault,
* reused for CCID by Alon Levy.
+ * Copyright (c) 2010 Red Hat.
*
* This code is licenced under the LGPL.
*/
+/* References:
+ *
+ * CCID Specification Revision 1.1 April 22nd 2005
+ * "Universal Serial Bus, Device Class: Smart Card"
+ * Specification for Integrated Circuit(s) Cards Interface Devices
+ *
+ */
+
/* TODO
*
- * Discard additional answers
- * Don't change answer while sending a multiple packet BULK_IN (answer_len > single_packet_len == 64)
+ * Discard additional answers (only one outstanding question per slot at a time
+ * according to spec). Don't change answer while sending a multiple packet
+ * BULK_IN (answer_len > single_packet_len == 64)
*
*/
@@ -22,7 +32,7 @@
#include "usb.h"
#include "qemu-char.h"
-#include "scard_common.h"
+#include "vscard_common.h"
#define DEBUG_CCID
@@ -35,8 +45,8 @@ do { printf("usb-ccid: " fmt , ## __VA_ARGS__); } while (0)
#define RECV_BUF 384
-#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
-#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
+#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
+#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
#define CCID_CONTROL_ABORT 0x1
#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x2
@@ -44,15 +54,15 @@ do { printf("usb-ccid: " fmt , ## __VA_ARGS__); } while (0)
#define IMPERSONATE_ATHENA
#ifdef IMPERSONATE_ATHENA
-#define CCID_PRODUCT_DESCRIPTION "ASEDrive CCID"
-#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION
-#define CCID_INTERFACE_NAME "CCID Interface"
-#define CCID_SERIAL_NUMBER_STRING "ASE016"
+#define CCID_PRODUCT_DESCRIPTION "ASEDrive CCID"
+#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION
+#define CCID_INTERFACE_NAME "CCID Interface"
+#define CCID_SERIAL_NUMBER_STRING "ASE016"
#else
-#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID"
-#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION
-#define CCID_INTERFACE_NAME "CCID Interface"
-#define CCID_SERIAL_NUMBER_STRING "1"
+#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID"
+#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION
+#define CCID_INTERFACE_NAME "CCID Interface"
+#define CCID_SERIAL_NUMBER_STRING "1"
#endif
// BULK_OUT messages from PC to Reader
@@ -89,9 +99,9 @@ do { printf("usb-ccid: " fmt , ## __VA_ARGS__); } while (0)
// To support slot insertion and removal we must have an interrupt in ep
// in addition we need a bulk in and bulk out ep
// 5.2, page 20
-#define CCID_INT_IN_EP 1
-#define CCID_BULK_IN_EP 2
-#define CCID_BULK_OUT_EP 3
+#define CCID_INT_IN_EP 1
+#define CCID_BULK_IN_EP 2
+#define CCID_BULK_OUT_EP 3
// bmSlotICCState masks
#define SLOT_0_STATE_MASK 1
@@ -116,17 +126,18 @@ enum {
// to transmit.
#define ERROR_NONE 0
enum {
- ERROR_CMD_ABORTED = -1,
- ERROR_ICC_MUTE = -2,
- ERROR_XFR_PARITY_ERROR = -3,
- ERROR_XFR_OVERRUN = -4,
- ERROR_HW_ERROR = -5,
+ ERROR_CMD_ABORTED = -1,
+ ERROR_ICC_MUTE = -2,
+ ERROR_XFR_PARITY_ERROR = -3,
+ ERROR_XFR_OVERRUN = -4,
+ ERROR_HW_ERROR = -5,
};
// 6.2.6 RDR_to_PC_SlotStatus definitions
enum {
- CLOCK_STATUS_RUNNING=0,
- // 0 - Clock Running, 1 - Clock stopped in State L, 2 - H, 3 - unkonwn state. rest are RFU
+ CLOCK_STATUS_RUNNING = 0,
+ // 0 - Clock Running, 1 - Clock stopped in State L, 2 - H,
+ // 3 - unkonwn state. rest are RFU
};
typedef struct __attribute__ ((__packed__)) {
@@ -184,8 +195,8 @@ typedef struct {
uint8_t bmSlotICCState;
} CCID_Notify_Slot_Change;
-#define MAX_ATR_SIZE 40
-#define MAX_PROTOCOL_SIZE 7
+#define MAX_ATR_SIZE 40
+#define MAX_PROTOCOL_SIZE 7
typedef struct {
USBDevice dev;
CharDriverState *cs;
@@ -205,6 +216,7 @@ typedef struct {
uint8_t bProtocolNum;
uint8_t abProtocolDataStructure[MAX_PROTOCOL_SIZE];
uint32_t ulProtocolDataStructureSize;
+ bool got_reader_add_message;
} USBCCIDState;
/* Slot specific variables. We emulate a single slot card reader.
@@ -221,10 +233,11 @@ uint8_t DEFAULT_ATR[] = {
/* CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
- * "USB Device Framework", section 9.6.1, in the Universal Serial Bus Specification.
+ * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
+ * Specification.
*
- * This device implemented based on the spec and with an Athena Smart Card Reader
- * as reference:
+ * This device implemented based on the spec and with an Athena Smart Card
+ * Reader as reference:
* 0dc3:1004 Athena Smartcard Solutions, Inc.
*/
@@ -347,55 +360,60 @@ static const uint8_t qemu_ccid_config_descriptor[] = {
/* Interrupt-IN endpoint */
0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */
- 0x80 | CCID_INT_IN_EP, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
+ /* u8 ep_bDescriptorType; Endpoint */
+ USB_DT_ENDPOINT,
+ /* u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x80 | CCID_INT_IN_EP,
0x03, /* u8 ep_bmAttributes; Interrupt */
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
0xff, /* u8 ep_bInterval; */
/* Bulk-In endpoint */
0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */
- 0x80 | CCID_BULK_IN_EP, /* u8 ep_bEndpointAddress; IN Endpoint 2 */
+ /* u8 ep_bDescriptorType; Endpoint */
+ USB_DT_ENDPOINT,
+ /* u8 ep_bEndpointAddress; IN Endpoint 2 */
+ 0x80 | CCID_BULK_IN_EP,
0x02, /* u8 ep_bmAttributes; Bulk */
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
0x00, /* u8 ep_bInterval; */
/* Bulk-Out endpoint */
0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */
- CCID_BULK_OUT_EP, /* u8 ep_bEndpointAddress; OUT Endpoint 3 */
+ /* u8 ep_bDescriptorType; Endpoint */
+ USB_DT_ENDPOINT,
+ /* u8 ep_bEndpointAddress; OUT Endpoint 3 */
+ CCID_BULK_OUT_EP,
0x02, /* u8 ep_bmAttributes; Bulk */
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
0x00, /* u8 ep_bInterval; */
};
-static void usb_ccid_reset(USBCCIDState *s)
+static void ccid_reset(USBCCIDState *s)
{
- /* TODO: Set flow control to none */
s->recv_ptr = 0;
s->recv_used = 0;
- /* TODO: purge in char driver */
+ s->got_reader_add_message = false;
}
-static void usb_ccid_handle_reset(USBDevice *dev)
+static void ccid_handle_reset(USBDevice *dev)
{
USBCCIDState *s = (USBCCIDState *)dev;
DPRINTF("Reset\n");
- usb_ccid_reset(s);
- /* TODO: Reset char device, send BREAK? */
+ ccid_reset(s);
+ /* TODO: Reset qemu chardev, send BREAK? SCMsg? */
}
-static int usb_ccid_handle_control(USBDevice *dev, int request, int value,
+static int ccid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
//USBCCIDState *s = (USBCCIDState *)dev;
int ret = 0;
- //DPRINTF("got control %x, value %x\n",request, value);
+ DPRINTF("got control %x, value %x\n",request, value);
switch (request) {
case DeviceRequest | USB_REQ_GET_STATUS:
data[0] = (0 << USB_DEVICE_SELF_POWERED) |
@@ -434,16 +452,6 @@ static int usb_ccid_handle_control(USBDevice *dev, int request, int value,
memcpy(data, qemu_ccid_config_descriptor,
sizeof(qemu_ccid_config_descriptor));
ret = sizeof(qemu_ccid_config_descriptor);
- /* I got a request with size 8 - even though the
- * basic descriptor is size 9. So handle it correctly.
- * byte zero is the length*/
- /* BROKEN - TODO?
- if (length < data[0]) {
- DPRINTF("Adjusting length of descriptor to requested length\n");
- data[0] = length;
- ret = length;
- }
- */
break;
case USB_DT_STRING:
switch(value & 0xff) {
@@ -500,15 +508,15 @@ static int usb_ccid_handle_control(USBDevice *dev, int request, int value,
/* Class specific requests. */
case DeviceOutVendor | CCID_CONTROL_ABORT:
- DPRINTF("ccid_control abort\n");
+ DPRINTF("ccid_control abort UNIMPLEMENTED\n");
ret = USB_RET_STALL;
break;
case DeviceOutVendor | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
- DPRINTF("ccid_control get clock frequencies\n");
+ DPRINTF("ccid_control get clock frequencies UNIMPLEMENTED\n");
ret = USB_RET_STALL;
break;
case DeviceOutVendor | CCID_CONTROL_GET_DATA_RATES:
- DPRINTF("ccid_control get data rates\n");
+ DPRINTF("ccid_control get data rates UNIMPLEMENTED\n");
ret = USB_RET_STALL;
break;
default:
@@ -523,7 +531,8 @@ static int usb_ccid_handle_control(USBDevice *dev, int request, int value,
static uint8_t* ccid_reserve_recv_buf(USBCCIDState* s, uint16_t len)
{
if (len + s->recv_used > RECV_BUF) {
- printf("usb-ccid.c: %s: overflow of receive buf. bailing out.\n", __func__);
+ printf("usb-ccid.c: %s: overflow of receive buf. bailing out.\n",
+ __func__);
exit(-1);
}
if (s->recv_used == 0) {
@@ -533,16 +542,19 @@ static uint8_t* ccid_reserve_recv_buf(USBCCIDState* s, uint16_t len)
return s->recv_buf + s->recv_ptr;
}
-static bool usb_ccid_card_inserted(USBCCIDState *s)
+static bool ccid_card_inserted(USBCCIDState *s)
{
return s->bmSlotICCState & SLOT_0_STATE_MASK;
}
-static uint8_t usb_ccid_calc_status(USBCCIDState *s)
+static uint8_t ccid_calc_status(USBCCIDState *s)
{
- // page 55, 6.2.6, calculation of bStatus from bmICCStatus and bmCommandStatus
- return (usb_ccid_card_inserted(s) ? ICC_STATUS_PRESENT_ACTIVE : ICC_STATUS_NOT_PRESENT)
- | (s->bmCommandStatus << 6);
+ // page 55, 6.2.6, calculation of bStatus from bmICCStatus and
+ // bmCommandStatus
+ return (ccid_card_inserted(s)
+ ? ICC_STATUS_PRESENT_ACTIVE
+ : ICC_STATUS_NOT_PRESENT)
+ | (s->bmCommandStatus << 6);
}
static void ccid_reset_error_status(USBCCIDState* s)
@@ -558,7 +570,7 @@ static void ccid_write_slot_status(USBCCIDState* s, CCID_Header* recv)
h->b.hdr.dwLength = 0;
h->b.hdr.bSlot = recv->bSlot;
h->b.hdr.bSeq = recv->bSeq;
- h->b.bStatus = usb_ccid_calc_status(s);
+ h->b.bStatus = ccid_calc_status(s);
h->b.bError = s->bError;
h->bClockStatus = CLOCK_STATUS_RUNNING;
ccid_reset_error_status(s);
@@ -574,7 +586,7 @@ static void ccid_write_parameters(USBCCIDState* s, CCID_Header* recv)
h->b.hdr.dwLength = 0;
h->b.hdr.bSlot = recv->bSlot;
h->b.hdr.bSeq = recv->bSeq;
- h->b.bStatus = usb_ccid_calc_status(s);
+ h->b.bStatus = ccid_calc_status(s);
h->b.bError = s->bError;
h->bProtocolNum = s->bProtocolNum;
memcpy(h->abProtocolDataStructure,s->abProtocolDataStructure, len);
@@ -595,7 +607,7 @@ static void ccid_write_data_block(
p->b.hdr.dwLength = len;
p->b.hdr.bSlot = slot;
p->b.hdr.bSeq = seq;
- p->b.bStatus = usb_ccid_calc_status(s);
+ p->b.bStatus = ccid_calc_status(s);
p->b.bError = s->bError;
memcpy(p->abData, data, len);
ccid_reset_error_status(s);
@@ -643,7 +655,7 @@ static void ccid_reset_parameters(USBCCIDState *s)
memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len);
}
-static void usb_ccid_on_slot_change(USBCCIDState* s, bool full)
+static void ccid_on_slot_change(USBCCIDState* s, bool full)
{
// RDR_to_PC_NotifySlotChange, 6.3.1 page 56
uint8_t current = s->bmSlotICCState;
@@ -658,20 +670,52 @@ static void usb_ccid_on_slot_change(USBCCIDState* s, bool full)
s->notify_slot_change = true;
}
-static void ccid_write_data_block_error(USBCCIDState *s, uint8_t slot, uint8_t seq)
+static void ccid_write_data_block_error(
+ USBCCIDState *s, uint8_t slot, uint8_t seq)
{
ccid_write_data_block(s, slot, seq, NULL, 0);
}
+static void ccid_vscard_send_msg(
+ USBCCIDState *s, VSCMsgType type, uint32_t reader_id,
+ uint8_t* payload, uint32_t length)
+{
+ VSCMsgHeader scr_msg_header;
+ scr_msg_header.type = type;
+ scr_msg_header.reader_id = reader_id;
+ scr_msg_header.length = length;
+ qemu_chr_write(s->cs, (uint8_t*)&scr_msg_header, sizeof(VSCMsgHeader));
+ qemu_chr_write(s->cs, payload, length);
+}
+
+static void ccid_vscard_send_apdu(
+ USBCCIDState *s, uint8_t* apdu, uint32_t length)
+{
+ ccid_vscard_send_msg(s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
+}
+
+static void ccid_vscard_send_error(
+ USBCCIDState *s, uint32_t reader_id, VSCErrorCode code)
+{
+ VSCMsgError msg = {.code=code};
+ ccid_vscard_send_msg(s, VSC_Error, reader_id, (uint8_t*)&msg, sizeof(msg));
+}
+
+static void ccid_vscard_send_init(USBCCIDState *s)
+{
+ VSCMsgInit msg = {.version=VSCARD_VERSION};
+ ccid_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
+ (uint8_t*)&msg, sizeof(msg));
+}
+
static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock* recv)
{
- static SCRMsgHeader scr_msg_header;
if (!s->cs) {
printf("usb-ccid: discarding apdu length %d\n", recv->hdr.dwLength);
return;
// XXX - dummy mode for testing, or just have the whole virtual card here.
}
- if (!usb_ccid_card_inserted(s)) {
+ if (!ccid_card_inserted(s)) {
printf("usb-ccid: not sending apdu to client, no card connected\n");
ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
return;
@@ -679,15 +723,11 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock* recv)
s->answer_slot = recv->hdr.bSlot;
s->answer_seq = recv->hdr.bSeq;
printf("usb-ccid: apdu_from_guest %d: len %d\n", recv->hdr.bSeq, recv->hdr.dwLength);
- scr_msg_header.type = SCard_APDU;
- scr_msg_header.nLength = recv->hdr.dwLength;
- // send request to remote card
- qemu_chr_write(s->cs, (uint8_t*)&scr_msg_header, sizeof(SCRMsgHeader));
- qemu_chr_write(s->cs, recv->abData, recv->hdr.dwLength);
+ ccid_vscard_send_apdu(s, recv->abData, recv->hdr.dwLength);
s->waiting_for_answer = true;
}
-static void usb_ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
+static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
{
static uint8_t data[70000]; // TODO - set to correct max size of packet.
static uint32_t len = 0;
@@ -737,7 +777,7 @@ static void usb_ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
len = 0;
}
-static int usb_ccid_handle_data(USBDevice *dev, USBPacket *p)
+static int ccid_handle_data(USBDevice *dev, USBPacket *p)
{
USBCCIDState *s = (USBCCIDState *)dev;
int ret = 0;
@@ -763,7 +803,7 @@ static int usb_ccid_handle_data(USBDevice *dev, USBPacket *p)
switch (p->pid) {
case USB_TOKEN_OUT:
- usb_ccid_handle_bulk_out(s, p);
+ ccid_handle_bulk_out(s, p);
break;
case USB_TOKEN_IN:
@@ -812,7 +852,7 @@ static int usb_ccid_handle_data(USBDevice *dev, USBPacket *p)
return ret;
}
-static void usb_ccid_handle_destroy(USBDevice *dev)
+static void ccid_handle_destroy(USBDevice *dev)
{
USBCCIDState *s = (USBCCIDState *)dev;
@@ -823,63 +863,73 @@ static void usb_ccid_handle_destroy(USBDevice *dev)
/* APDU chardev */
-static int usb_ccid_scard_can_read(void *opaque)
+static int ccid_scard_can_read(void *opaque)
{
//USBCCIDState *s = opaque;
return 70000; // XXX number has meaning, or just positive for yes?
}
-static void usb_ccid_scard_read(void *opaque, const uint8_t *buf, int size)
+static void ccid_vscard_read(void *opaque, const uint8_t *buf, int size)
{
static uint8_t readbuf[10000];
static uint32_t readpos = 0;
USBCCIDState *s = opaque;
- const SCRMsgHeader* scr_msg_header = (const SCRMsgHeader*)readbuf;
- const uint8_t* data = readbuf + sizeof(SCRMsgHeader);
+ const VSCMsgHeader* scr_msg_header = (const VSCMsgHeader*)readbuf;
+ const uint8_t* data = readbuf + sizeof(VSCMsgHeader);
uint32_t available = size + readpos;
assert(readpos + size <= sizeof(readbuf));
memcpy(readbuf + readpos, buf, size);
readpos += size;
- if (available - sizeof(SCRMsgHeader) < scr_msg_header->nLength) {
+ if (available - sizeof(VSCMsgHeader) < scr_msg_header->length) {
return;
}
readpos = 0; // ready for next message
switch (scr_msg_header->type) {
- case SCard_ATR:
- DPRINTF("SCard_ATR %d\n", scr_msg_header->nLength);
- assert(scr_msg_header->nLength <= MAX_ATR_SIZE);
- memcpy(s->atr, data, scr_msg_header->nLength);
- s->atr_length = scr_msg_header->nLength;
+ case VSC_ATR:
+ DPRINTF("VSC_ATR %d\n", scr_msg_header->length);
+ assert(scr_msg_header->length <= MAX_ATR_SIZE);
+ memcpy(s->atr, data, scr_msg_header->length);
+ s->atr_length = scr_msg_header->length;
s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
- usb_ccid_on_slot_change(s, true);
+ ccid_on_slot_change(s, true);
break;
- case SCard_APDU:
+ case VSC_APDU:
if (!s->waiting_for_answer) {
- DPRINTF("SCard_APDU: ERROR: got an APDU while not waiting_for_answer\n");
+ DPRINTF("VSC_APDU: ERROR: got an APDU while not waiting_for_answer\n");
assert(s->waiting_for_answer);
}
s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
- DPRINTF("SCard_APDU %d (answer seq %d, slot %d)\n",
- scr_msg_header->nLength,
+ DPRINTF("VSC_APDU %d (answer seq %d, slot %d)\n",
+ scr_msg_header->length,
s->answer_seq, s->answer_slot);
- ccid_write_data_block_answer(s, data, scr_msg_header->nLength);
+ ccid_write_data_block_answer(s, data, scr_msg_header->length);
break;
- case SCard_Remove:
- DPRINTF("SCard_Remove\n");
- usb_ccid_on_slot_change(s, false);
+ case VSC_CardRemove:
+ DPRINTF("VSC_CardRemove\n");
+ ccid_on_slot_change(s, false);
if (s->waiting_for_answer) {
ccid_write_data_block_answer(s, NULL, 0);
}
break;
- case SCard_Error:
+ case VSC_Init:
+ ccid_vscard_send_init(s);
+ break;
+ case VSC_ReaderAdd:
+ if (!s->got_reader_add_message) {
+ s->got_reader_add_message = true;
+ } else {
+ ccid_vscard_send_error(s, VSCARD_UNDEFINED_READER_ID,
+ VSC_CANNOT_ADD_MORE_READERS);
+ }
+ case VSC_Error:
// TODO - actually look at the error
s->bmCommandStatus = COMMAND_STATUS_FAILED;
s->last_answer_error = *(uint64_t*)data;
- DPRINTF("SCard_Error: %lX\n", s->last_answer_error);
+ DPRINTF("VSC_Error: %lX\n", s->last_answer_error);
ccid_write_data_block_answer(s, NULL, 0);
break;
default:
@@ -891,14 +941,23 @@ static void usb_ccid_scard_read(void *opaque, const uint8_t *buf, int size)
}
}
-static void usb_ccid_scard_event(void *opaque, int event)
+static void ccid_scard_event(void *opaque, int event)
{
- //USBCCIDState *s = opaque;
+ USBCCIDState *s = opaque;
+ switch (event) {
+ case CHR_EVENT_BREAK:
+ break;
+ case CHR_EVENT_FOCUS:
+ break;
+ case CHR_EVENT_OPENED:
+ ccid_reset(s);
+ break;
+ }
}
/* Control chardev */
-static int usb_ccid_initfn(USBDevice *dev)
+static int ccid_initfn(USBDevice *dev)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
s->dev.speed = USB_SPEED_FULL;
@@ -911,13 +970,16 @@ static int usb_ccid_initfn(USBDevice *dev)
assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
memcpy(s->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
s->atr_length = sizeof(DEFAULT_ATR);
+ s->got_reader_add_message = false;
if (s->cs) {
DPRINTF("initing chardev\n");
- qemu_chr_add_handlers(s->cs, usb_ccid_scard_can_read, usb_ccid_scard_read,
- usb_ccid_scard_event, s);
+ qemu_chr_add_handlers(s->cs,
+ ccid_scard_can_read,
+ ccid_vscard_read,
+ ccid_scard_event, s);
}
ccid_reset_parameters(s);
- usb_ccid_handle_reset(dev);
+ ccid_handle_reset(dev);
return 0;
}
@@ -925,12 +987,12 @@ static struct USBDeviceInfo ccid_info = {
.product_desc = "QEMU USB CCID",
.qdev.name = "usb-ccid",
.qdev.size = sizeof(USBCCIDState),
- .init = usb_ccid_initfn,
+ .init = ccid_initfn,
.handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_ccid_handle_reset,
- .handle_control = usb_ccid_handle_control,
- .handle_data = usb_ccid_handle_data,
- .handle_destroy = usb_ccid_handle_destroy,
+ .handle_reset = ccid_handle_reset,
+ .handle_control = ccid_handle_control,
+ .handle_data = ccid_handle_data,
+ .handle_destroy = ccid_handle_destroy,
.usbdevice_name = "ccid",
.qdev.props = (Property[]) {
DEFINE_PROP_CHR("chardev", USBCCIDState, cs),
@@ -938,8 +1000,8 @@ static struct USBDeviceInfo ccid_info = {
},
};
-static void usb_ccid_register_devices(void)
+static void ccid_register_devices(void)
{
usb_qdev_register(&ccid_info);
}
-device_init(usb_ccid_register_devices)
+device_init(ccid_register_devices)
diff --git a/vscard_common.h b/vscard_common.h
new file mode 100644
index 000000000..38ffdf2ba
--- /dev/null
+++ b/vscard_common.h
@@ -0,0 +1,118 @@
+/* Virtual Smart Card protocol definition
+ *
+ * This protocol is between a host implementing a group of virtual smart card
+ * reader, and a client implementing a virtual smart card, or passthrough to
+ * a real card.
+ *
+ * The current implementation passes the raw APDU's from 7816 and additionally
+ * contains messages to setup and teardown readers, handle insertion and
+ * removal of cards, negotiate the protocol and provide for error responses.
+ *
+ * Copyright (c) 2010 Red Hat.
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#ifndef _VSCARD_COMMON_H
+#define _VSCARD_COMMON_H
+
+
+#define VERSION_MAJOR_BITS 11
+#define VERSION_MIDDLE_BITS 11
+#define VERSION_MINOR_BITS 10
+
+#define MAKE_VERSION(major, middle, minor) \
+ ( (major << (VERSION_MINOR_BITS + VERSION_MIDDLE_BITS)) \
+ | (middle << VERSION_MINOR_BITS) \
+ | (minor) )
+
+/** IMPORTANT NOTE on VERSION
+ *
+ * The version below MUST be changed whenever a change in this file is made.
+ *
+ * The last digit, the minor, is for bug fix changes only.
+ *
+ * The middle digit is for backward / forward compatible changes, updates
+ * to the existing messages, addition of fields.
+ *
+ * The major digit is for a breaking change of protocol, presumably
+ * something that cannot be accomodated with the existing protocol.
+ */
+
+#define VSCARD_VERSION MAKE_VERSION(0,0,1)
+
+#define VSCARD_UNDEFINED_READER_ID -1
+#define VSCARD_MINIMAL_READER_ID 0
+
+typedef enum {
+ VSC_Init,
+ VSC_Error,
+ VSC_ReaderAdd,
+ VSC_ReaderAddResponse,
+ VSC_ReaderRemove,
+ VSC_ATR,
+ VSC_CardRemove,
+ VSC_APDU
+} VSCMsgType;
+
+typedef enum {
+ VSC_GENERAL_ERROR=1,
+ VSC_CANNOT_ADD_MORE_READERS,
+} VSCErrorCode;
+
+typedef struct VSCMsgHeader {
+ VSCMsgType type;
+ uint32_t reader_id;
+ uint32_t length;
+} VSCMsgHeader;
+
+/* VSCMsgInit Client <-> Host
+ * Host replies with allocated reader id in ReaderAddResponse
+ * */
+typedef struct VSCMsgInit {
+ uint32_t version;
+} VSCMsgInit;
+
+/* VSCMsgError Client <-> Host
+ * */
+typedef struct VSCMsgError {
+ VSCErrorCode code;
+} VSCMsgError;
+
+/* VSCMsgReaderAdd Client -> Host
+ * Host replies with allocated reader id in ReaderAddResponse
+ * */
+typedef struct VSCMsgReaderAdd {
+ uint8_t name[0];
+} VSCMsgReaderAdd;
+
+/* VSCMsgReaderAddResponse Host -> Client
+ * Reply to ReaderAdd
+ * */
+typedef struct VSCMsgReaderAddResponse {
+} VSCMsgReaderAddResponse;
+
+/* VSCMsgReaderRemove Client -> Host
+ * */
+typedef struct VSCMsgReaderRemove {
+} VSCMsgReaderRemove;
+
+/* VSCMsgATR Client -> Host
+ * Answer to reset. Sent for card insertion or card reset.
+ * */
+typedef struct VSCMsgATR {
+ uint8_t atr[0];
+} VSCMsgATR;
+
+/* VSCMsgCardRemove Client -> Host
+ * */
+typedef struct VSCMsgCardRemove {
+} VSCMsgCardRemove;
+
+/* VSCMsgAPDU Client <-> Host
+ * */
+typedef struct VSCMsgAPDU {
+ uint8_t data[0];
+} VSCMsgAPDU;
+
+#endif