]> Git Repo - qemu.git/blobdiff - hw/usb-ccid.c
qom: Unify type registration
[qemu.git] / hw / usb-ccid.c
index 66aeb211af4ba52f8dea593a15149455825862d4..893d0a0deff7b8a8e2746c58af9d26759799b03b 100644 (file)
@@ -37,6 +37,7 @@
 #include "qemu-common.h"
 #include "qemu-error.h"
 #include "usb.h"
+#include "usb-desc.h"
 #include "monitor.h"
 
 #include "hw/ccid.h"
@@ -176,56 +177,56 @@ enum {
      */
 };
 
-typedef struct __attribute__ ((__packed__)) CCID_Header {
+typedef struct QEMU_PACKED CCID_Header {
     uint8_t     bMessageType;
     uint32_t    dwLength;
     uint8_t     bSlot;
     uint8_t     bSeq;
 } CCID_Header;
 
-typedef struct __attribute__ ((__packed__)) CCID_BULK_IN {
+typedef struct QEMU_PACKED CCID_BULK_IN {
     CCID_Header hdr;
     uint8_t     bStatus;        /* Only used in BULK_IN */
     uint8_t     bError;         /* Only used in BULK_IN */
 } CCID_BULK_IN;
 
-typedef struct __attribute__ ((__packed__)) CCID_SlotStatus {
+typedef struct QEMU_PACKED CCID_SlotStatus {
     CCID_BULK_IN b;
     uint8_t     bClockStatus;
 } CCID_SlotStatus;
 
-typedef struct __attribute__ ((__packed__)) CCID_Parameter {
+typedef struct QEMU_PACKED CCID_Parameter {
     CCID_BULK_IN b;
     uint8_t     bProtocolNum;
     uint8_t     abProtocolDataStructure[0];
 } CCID_Parameter;
 
-typedef struct __attribute__ ((__packed__)) CCID_DataBlock {
+typedef struct QEMU_PACKED CCID_DataBlock {
     CCID_BULK_IN b;
     uint8_t      bChainParameter;
     uint8_t      abData[0];
 } CCID_DataBlock;
 
 /* 6.1.4 PC_to_RDR_XfrBlock */
-typedef struct __attribute__ ((__packed__)) CCID_XferBlock {
+typedef struct QEMU_PACKED CCID_XferBlock {
     CCID_Header  hdr;
     uint8_t      bBWI; /* Block Waiting Timeout */
     uint16_t     wLevelParameter; /* XXX currently unused */
     uint8_t      abData[0];
 } CCID_XferBlock;
 
-typedef struct __attribute__ ((__packed__)) CCID_IccPowerOn {
+typedef struct QEMU_PACKED CCID_IccPowerOn {
     CCID_Header hdr;
     uint8_t     bPowerSelect;
     uint16_t    abRFU;
 } CCID_IccPowerOn;
 
-typedef struct __attribute__ ((__packed__)) CCID_IccPowerOff {
+typedef struct QEMU_PACKED CCID_IccPowerOff {
     CCID_Header hdr;
     uint16_t    abRFU;
 } CCID_IccPowerOff;
 
-typedef struct __attribute__ ((__packed__)) CCID_SetParameters {
+typedef struct QEMU_PACKED CCID_SetParameters {
     CCID_Header hdr;
     uint8_t     bProtocolNum;
     uint16_t   abRFU;
@@ -268,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 */
@@ -306,56 +306,7 @@ typedef struct USBCCIDState {
  *   0dc3:1004 Athena Smartcard Solutions, Inc.
  */
 
-static const uint8_t qemu_ccid_dev_descriptor[] = {
-        0x12,       /*  u8 bLength; */
-        USB_DT_DEVICE, /*  u8 bDescriptorType; Device */
-        0x10, 0x01, /*  u16 bcdUSB; v1.1 */
-
-        0x00,       /*  u8  bDeviceClass; */
-        0x00,       /*  u8  bDeviceSubClass; */
-        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
-        0x40,       /*  u8  bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */
-
-        /* Vendor and product id are arbitrary.  */
-                    /*  u16 idVendor  */
-        CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8,
-                    /*  u16 idProduct */
-        CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8,
-                    /*  u16 bcdDevice */
-        CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8,
-        0x01,       /*  u8  iManufacturer; */
-        0x02,       /*  u8  iProduct; */
-        0x03,       /*  u8  iSerialNumber; */
-        0x01,       /*  u8  bNumConfigurations; */
-};
-
-static const uint8_t qemu_ccid_config_descriptor[] = {
-
-        /* one configuration */
-        0x09,       /* u8  bLength; */
-        USB_DT_CONFIG, /* u8  bDescriptorType; Configuration */
-        0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */
-        0x01,       /* u8  bNumInterfaces; (1) */
-        0x01,       /* u8  bConfigurationValue; */
-        0x00,       /* u8  iConfiguration; */
-        0xe0,       /* u8  bmAttributes;
-                                 Bit 7: must be set,
-                                     6: Self-powered,
-                                     5: Remote wakeup,
-                                     4..0: resvd */
-        100/2,      /* u8  MaxPower; 50 == 100mA */
-
-        /* one interface */
-        0x09,       /* u8  if_bLength; */
-        USB_DT_INTERFACE, /* u8  if_bDescriptorType; Interface */
-        0x00,       /* u8  if_bInterfaceNumber; */
-        0x00,       /* u8  if_bAlternateSetting; */
-        0x03,       /* u8  if_bNumEndpoints; */
-        0x0b,       /* u8  if_bInterfaceClass; Smart Card Device Class */
-        0x00,       /* u8  if_bInterfaceSubClass; Subclass code */
-        0x00,       /* u8  if_bInterfaceProtocol; Protocol code */
-        0x04,       /* u8  if_iInterface; Index of string descriptor */
-
+static const uint8_t qemu_ccid_descriptor[] = {
         /* Smart Card Device Class Descriptor */
         0x36,       /* u8  bLength; */
         0x21,       /* u8  bDescriptorType; Functional */
@@ -439,40 +390,120 @@ static const uint8_t qemu_ccid_config_descriptor[] = {
                      *                  02h PIN Modification
                      */
         0x01,       /* u8  bMaxCCIDBusySlots; */
+};
+
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_INTERFACE,
+};
 
-        /* Interrupt-IN endpoint */
-        0x07,       /* u8  ep_bLength; */
-                    /* u8  ep_bDescriptorType; Endpoint */
-        USB_DT_ENDPOINT,
-                    /* u8  ep_bEndpointAddress; IN Endpoint 1 */
-        0x80 | CCID_INT_IN_EP,
-        0x03,       /* u8  ep_bmAttributes; Interrupt */
-                    /* u16 ep_wMaxPacketSize; */
-        CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8),
-        0xff,       /* u8  ep_bInterval; */
-
-        /* Bulk-In endpoint */
-        0x07,       /* u8  ep_bLength; */
-                    /* 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; */
-                    /* 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 const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]  = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]       = "QEMU USB CCID",
+    [STR_SERIALNUMBER]  = "1",
+    [STR_INTERFACE]     = "CCID Interface",
+};
 
+static const USBDescIface desc_iface0 = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = 0x0b,
+    .bInterfaceSubClass            = 0x00,
+    .bInterfaceProtocol            = 0x00,
+    .iInterface                    = STR_INTERFACE,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* smartcard descriptor */
+            .data = qemu_ccid_descriptor,
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | CCID_INT_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .bInterval             = 255,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | CCID_BULK_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | CCID_BULK_OUT_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    }
 };
 
+static const USBDescDevice desc_device = {
+    .bcdUSB                        = 0x0110,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0xa0,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface0,
+        },
+    },
+};
+
+static const USBDesc desc_ccid = {
+    .id = {
+        .idVendor          = CCID_VENDOR_ID,
+        .idProduct         = CCID_PRODUCT_ID,
+        .bcdDevice         = CCID_DEVICE_VERSION,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .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;
@@ -610,98 +641,12 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
     int ret = 0;
 
     DPRINTF(s, 1, "got control %x, value %x\n", request, value);
-    switch (request) {
-    case DeviceRequest | USB_REQ_GET_STATUS:
-        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
-            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
-        data[1] = 0x00;
-        ret = 2;
-        break;
-    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 0;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 1;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
-        dev->addr = value;
-        ret = 0;
-        break;
-    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch (value >> 8) {
-        case USB_DT_DEVICE:
-            memcpy(data, qemu_ccid_dev_descriptor,
-                   sizeof(qemu_ccid_dev_descriptor));
-            ret = sizeof(qemu_ccid_dev_descriptor);
-            break;
-        case USB_DT_CONFIG:
-            memcpy(data, qemu_ccid_config_descriptor,
-                   sizeof(qemu_ccid_config_descriptor));
-            ret = sizeof(qemu_ccid_config_descriptor);
-            break;
-        case USB_DT_STRING:
-            switch (value & 0xff) {
-            case 0:
-                /* language ids */
-                data[0] = 4;
-                data[1] = 3;
-                data[2] = 0x09;
-                data[3] = 0x04;
-                ret = 4;
-                break;
-            case 1:
-                /* vendor description */
-                ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION);
-                break;
-            case 2:
-                /* product description */
-                ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION);
-                break;
-            case 3:
-                /* serial number */
-                ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING);
-                break;
-            case 4:
-                /* interface name */
-                ret = set_usb_string(data, CCID_INTERFACE_NAME);
-                break;
-            default:
-                goto fail;
-            }
-            break;
-        default:
-            goto fail;
-        }
-        break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        /* Only one configuration - we just ignore the request */
-        ret = 0;
-        break;
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
-    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
-        ret = 0;
-        break;
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
 
+    switch (request) {
         /* Class specific requests.  */
     case InterfaceOutClass | CCID_CONTROL_ABORT:
         DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
@@ -716,7 +661,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
         ret = USB_RET_STALL;
         break;
     default:
-fail:
         DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
                 request, value);
         ret = USB_RET_STALL;
@@ -833,7 +777,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);
 }
@@ -895,6 +839,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
     }
     s->notify_slot_change = true;
+    usb_wakeup(&s->dev);
 }
 
 static void ccid_write_data_block_error(
@@ -918,7 +863,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");
     }
@@ -1075,6 +1020,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
             break;
         default:
             DPRINTF(s, 1, "Bad endpoint\n");
+            ret = USB_RET_STALL;
             break;
         }
         break;
@@ -1203,26 +1149,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->info);
+    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)
+static int ccid_card_init(DeviceState *qdev)
 {
-    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;
@@ -1236,30 +1177,21 @@ 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)
-{
-    card->qdev.bus_info = &ccid_bus_info;
-    card->qdev.init = ccid_card_init;
-    card->qdev.exit = ccid_card_exit;
-    qdev_register(&card->qdev);
-}
-
 static int ccid_initfn(USBDevice *dev)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
 
+    usb_desc_init(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;
@@ -1375,27 +1307,58 @@ static VMStateDescription ccid_vmstate = {
     }
 };
 
-static struct USBDeviceInfo ccid_info = {
-    .product_desc   = "QEMU USB CCID",
-    .qdev.name      = CCID_DEV_NAME,
-    .qdev.desc      = "CCID Rev 1.1 smartcard reader",
-    .qdev.size      = sizeof(USBCCIDState),
-    .init           = ccid_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .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_UINT8("debug", USBCCIDState, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
-    .qdev.vmsd      = &ccid_vmstate,
+static Property ccid_properties[] = {
+    DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccid_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = ccid_initfn;
+    uc->product_desc   = "QEMU USB CCID";
+    uc->usb_desc       = &desc_ccid;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = ccid_handle_reset;
+    uc->handle_control = ccid_handle_control;
+    uc->handle_data    = ccid_handle_data;
+    uc->handle_destroy = ccid_handle_destroy;
+    dc->desc = "CCID Rev 1.1 smartcard reader";
+    dc->vmsd = &ccid_vmstate;
+    dc->props = ccid_properties;
+}
+
+static TypeInfo ccid_info = {
+    .name          = CCID_DEV_NAME,
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBCCIDState),
+    .class_init    = ccid_class_initfn,
 };
 
-static void ccid_register_devices(void)
+static void ccid_card_class_init(ObjectClass *klass, void *data)
 {
-    usb_qdev_register(&ccid_info);
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->bus_info = &ccid_bus_info;
+    k->init = ccid_card_init;
+    k->exit = ccid_card_exit;
 }
-device_init(ccid_register_devices)
+
+static TypeInfo ccid_card_type_info = {
+    .name = TYPE_CCID_CARD,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(CCIDCardState),
+    .abstract = true,
+    .class_size = sizeof(CCIDCardClass),
+    .class_init = ccid_card_class_init,
+};
+
+static void ccid_register_types(void)
+{
+    type_register_static(&ccid_card_type_info);
+    type_register_static(&ccid_info);
+    usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
+}
+
+type_init(ccid_register_types)
This page took 0.041022 seconds and 4 git commands to generate.