diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 2d2ebce..6dabe7a 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -564,16 +564,23 @@ static int emulated_exitfn(CCIDCardState *base)
     return 0;
 }
 
-static CCIDCardInfo emulated_card_info = {
-    .qdev.name = EMULATED_DEV_NAME,
-    .qdev.desc = "emulated smartcard",
-    .qdev.size = sizeof(EmulatedState),
-    .initfn = emulated_initfn,
-    .exitfn = emulated_exitfn,
-    .get_atr = emulated_get_atr,
-    .apdu_from_guest = emulated_apdu_from_guest,
-    .qdev.unplug    = qdev_simple_unplug_cb,
-    .qdev.props     = (Property[]) {
+static void emulated_class_initfn(ObjectClass *klass, void *data)
+{
+    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+    cc->initfn = emulated_initfn;
+    cc->exitfn = emulated_exitfn;
+    cc->get_atr = emulated_get_atr;
+    cc->apdu_from_guest = emulated_apdu_from_guest;
+}
+
+static DeviceInfo emulated_card_info = {
+    .name = EMULATED_DEV_NAME,
+    .desc = "emulated smartcard",
+    .size = sizeof(EmulatedState),
+    .unplug    = qdev_simple_unplug_cb,
+    .class_init = emulated_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
         DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
         DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index 9f51c6c..f563d97 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -316,16 +316,23 @@ static VMStateDescription passthru_vmstate = {
     }
 };
 
-static CCIDCardInfo passthru_card_info = {
-    .qdev.name = PASSTHRU_DEV_NAME,
-    .qdev.desc = "passthrough smartcard",
-    .qdev.size = sizeof(PassthruState),
-    .qdev.vmsd = &passthru_vmstate,
-    .initfn = passthru_initfn,
-    .exitfn = passthru_exitfn,
-    .get_atr = passthru_get_atr,
-    .apdu_from_guest = passthru_apdu_from_guest,
-    .qdev.props     = (Property[]) {
+static void passthru_class_initfn(ObjectClass *klass, void *data)
+{
+    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+    cc->initfn = passthru_initfn;
+    cc->exitfn = passthru_exitfn;
+    cc->get_atr = passthru_get_atr;
+    cc->apdu_from_guest = passthru_apdu_from_guest;
+}
+
+static DeviceInfo passthru_card_info = {
+    .name = PASSTHRU_DEV_NAME,
+    .desc = "passthrough smartcard",
+    .size = sizeof(PassthruState),
+    .vmsd = &passthru_vmstate,
+    .class_init = passthru_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_CHR("chardev", PassthruState, cs),
         DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
         DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/ccid.h b/hw/ccid.h
index 9e3abe1..9e4979c 100644
--- a/hw/ccid.h
+++ b/hw/ccid.h
@@ -15,26 +15,34 @@
 typedef struct CCIDCardState CCIDCardState;
 typedef struct CCIDCardInfo CCIDCardInfo;
 
-/*
- * state of the CCID Card device (i.e. hw/ccid-card-*.c)
- */
-struct CCIDCardState {
-    DeviceState qdev;
-    uint32_t    slot; /* For future use with multiple slot reader. */
-};
+#define TYPE_CCID_CARD "ccid-card"
+#define CCID_CARD(obj) \
+     OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD)
+#define CCID_CARD_CLASS(klass) \
+     OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD)
+#define CCID_CARD_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD)
 
 /*
  * callbacks to be used by the CCID device (hw/usb-ccid.c) to call
  * into the smartcard device (hw/ccid-card-*.c)
  */
-struct CCIDCardInfo {
-    DeviceInfo qdev;
+typedef struct CCIDCardClass {
+    DeviceClass parent_class;
     const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
     void (*apdu_from_guest)(CCIDCardState *card,
                             const uint8_t *apdu,
                             uint32_t len);
     int (*exitfn)(CCIDCardState *card);
     int (*initfn)(CCIDCardState *card);
+} CCIDCardClass;
+
+/*
+ * state of the CCID Card device (i.e. hw/ccid-card-*.c)
+ */
+struct CCIDCardState {
+    DeviceState qdev;
+    uint32_t    slot; /* For future use with multiple slot reader. */
 };
 
 /*
@@ -46,7 +54,7 @@ void ccid_card_send_apdu_to_guest(CCIDCardState *card,
 void ccid_card_card_removed(CCIDCardState *card);
 void ccid_card_card_inserted(CCIDCardState *card);
 void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-void ccid_card_qdev_register(CCIDCardInfo *card);
+void ccid_card_qdev_register(DeviceInfo *card);
 
 /*
  * support guest visible insertion/removal of ccid devices based on actual
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 47b1120..a803c71 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -269,7 +269,6 @@ typedef struct USBCCIDState {
     USBDevice dev;
     CCIDBus bus;
     CCIDCardState *card;
-    CCIDCardInfo *cardinfo; /* caching the info pointer */
     BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
     uint32_t bulk_in_pending_start;
     uint32_t bulk_in_pending_end; /* first free */
@@ -468,6 +467,43 @@ static const USBDesc desc_ccid = {
     .str  = desc_strings,
 };
 
+static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->get_atr) {
+        return cc->get_atr(card, len);
+    }
+    return NULL;
+}
+
+static void ccid_card_apdu_from_guest(CCIDCardState *card,
+                                      const uint8_t *apdu,
+                                      uint32_t len)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->apdu_from_guest) {
+        cc->apdu_from_guest(card, apdu, len);
+    }
+}
+
+static int ccid_card_exitfn(CCIDCardState *card)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->exitfn) {
+        return cc->exitfn(card);
+    }
+    return 0;
+}
+
+static int ccid_card_initfn(CCIDCardState *card)
+{
+    CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+    if (cc->initfn) {
+        return cc->initfn(card);
+    }
+    return 0;
+}
+
 static bool ccid_has_pending_answers(USBCCIDState *s)
 {
     return s->pending_answers_num > 0;
@@ -749,7 +785,7 @@ static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
     uint32_t len = 0;
 
     if (s->card) {
-        atr = s->cardinfo->get_atr(s->card, &len);
+        atr = ccid_card_get_atr(s->card, &len);
     }
     ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
 }
@@ -835,7 +871,7 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
                 recv->hdr.bSeq, len);
     ccid_add_pending_answer(s, (CCID_Header *)recv);
     if (s->card) {
-        s->cardinfo->apdu_from_guest(s->card, recv->abData, len);
+        ccid_card_apdu_from_guest(s->card, recv->abData, len);
     } else {
         DPRINTF(s, D_WARN, "warning: discarded apdu\n");
     }
@@ -1121,26 +1157,21 @@ void ccid_card_card_inserted(CCIDCardState *card)
 static int ccid_card_exit(DeviceState *qdev)
 {
     int ret = 0;
-    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
-    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev_get_info(qdev));
+    CCIDCardState *card = CCID_CARD(qdev);
     USBCCIDState *s =
         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
 
     if (ccid_card_inserted(s)) {
         ccid_card_card_removed(card);
     }
-    if (info->exitfn) {
-        ret = info->exitfn(card);
-    }
+    ret = ccid_card_exitfn(card);
     s->card = NULL;
-    s->cardinfo = NULL;
     return ret;
 }
 
 static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
 {
-    CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
-    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base);
+    CCIDCardState *card = CCID_CARD(qdev);
     USBCCIDState *s =
         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
     int ret = 0;
@@ -1154,20 +1185,19 @@ static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
         error_report("Warning: usb-ccid card already full, not adding");
         return -1;
     }
-    ret = info->initfn ? info->initfn(card) : ret;
+    ret = ccid_card_initfn(card);
     if (ret == 0) {
         s->card = card;
-        s->cardinfo = info;
     }
     return ret;
 }
 
-void ccid_card_qdev_register(CCIDCardInfo *card)
+void ccid_card_qdev_register(DeviceInfo *info)
 {
-    card->qdev.bus_info = &ccid_bus_info;
-    card->qdev.init = ccid_card_init;
-    card->qdev.exit = ccid_card_exit;
-    qdev_register(&card->qdev);
+    info->bus_info = &ccid_bus_info;
+    info->init = ccid_card_init;
+    info->exit = ccid_card_exit;
+    qdev_register_subclass(info, TYPE_CCID_CARD);
 }
 
 static int ccid_initfn(USBDevice *dev)
@@ -1178,7 +1208,6 @@ static int ccid_initfn(USBDevice *dev)
     qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
     s->bus.qbus.allow_hotplug = 1;
     s->card = NULL;
-    s->cardinfo = NULL;
     s->migration_state = MIGRATION_NONE;
     s->migration_target_ip = 0;
     s->migration_target_port = 0;
@@ -1320,8 +1349,17 @@ static struct DeviceInfo ccid_info = {
     },
 };
 
+static TypeInfo ccid_card_type_info = {
+    .name = TYPE_CCID_CARD,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(CCIDCardState),
+    .abstract = true,
+    .class_size = sizeof(CCIDCardClass),
+};
+
 static void ccid_register_devices(void)
 {
+    type_register_static(&ccid_card_type_info);
     usb_qdev_register(&ccid_info, "ccid", NULL);
 }
 device_init(ccid_register_devices)
