Patchwork [V2,06/10] hw/sd.c: convert to QOM object

login
register
mail settings
Submitter Mitsyanko Igor
Date April 5, 2012, 3:48 p.m.
Message ID <1333640913-16028-7-git-send-email-i.mitsyanko@samsung.com>
Download mbox | patch
Permalink /patch/151089/
State New
Headers show

Comments

Mitsyanko Igor - April 5, 2012, 3:48 p.m.
A straightforward conversion of SD card implementation to a proper QEMU object.

Signed-off-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
---
 hw/milkymist-memcard.c |   24 ++++++++++++++----------
 hw/omap_mmc.c          |   28 ++++++++++++++++------------
 hw/pl181.c             |   14 ++++++++------
 hw/pxa2xx_mmci.c       |   22 ++++++++++++++--------
 hw/sd.c                |   48 +++++++++++++++++++++++++++++++++++++-----------
 hw/sd.h                |   38 ++++++++++++++++++++++++++++++--------
 hw/ssi-sd.c            |   11 ++++++-----
 7 files changed, 125 insertions(+), 60 deletions(-)
Peter Maydell - April 11, 2012, 10:26 a.m.
On 5 April 2012 16:48, Igor Mitsyanko <i.mitsyanko@samsung.com> wrote:
> A straightforward conversion of SD card implementation to a proper QEMU object.
>
> Signed-off-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
> ---
>  hw/milkymist-memcard.c |   24 ++++++++++++++----------
>  hw/omap_mmc.c          |   28 ++++++++++++++++------------
>  hw/pl181.c             |   14 ++++++++------
>  hw/pxa2xx_mmci.c       |   22 ++++++++++++++--------
>  hw/sd.c                |   48 +++++++++++++++++++++++++++++++++++++-----------
>  hw/sd.h                |   38 ++++++++++++++++++++++++++++++--------
>  hw/ssi-sd.c            |   11 ++++++-----
>  7 files changed, 125 insertions(+), 60 deletions(-)
>
> diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
> index 3515c3c..1d84d44 100644
> --- a/hw/milkymist-memcard.c
> +++ b/hw/milkymist-memcard.c
> @@ -97,7 +97,7 @@ static void memcard_sd_command(MilkymistMemcardState *s)
>     req.crc = s->command[5];
>
>     s->response[0] = req.cmd;
> -    s->response_len = sd_do_command(s->card, &req, s->response+1);
> +    s->response_len = SD_DO_COMMAND(s->card, &req, s->response + 1);

Does our object model really demand this kind of conversion to all-caps?
Seems kind of ugly and churny :-(

-- PMM
Mitsyanko Igor - April 11, 2012, 11:14 a.m.
On 04/11/2012 02:26 PM, Peter Maydell wrote:
> On 5 April 2012 16:48, Igor Mitsyanko<i.mitsyanko@samsung.com>  wrote:
>> A straightforward conversion of SD card implementation to a proper QEMU object.
>>
>> Signed-off-by: Igor Mitsyanko<i.mitsyanko@samsung.com>
>> ---
>>   hw/milkymist-memcard.c |   24 ++++++++++++++----------
>>   hw/omap_mmc.c          |   28 ++++++++++++++++------------
>>   hw/pl181.c             |   14 ++++++++------
>>   hw/pxa2xx_mmci.c       |   22 ++++++++++++++--------
>>   hw/sd.c                |   48 +++++++++++++++++++++++++++++++++++++-----------
>>   hw/sd.h                |   38 ++++++++++++++++++++++++++++++--------
>>   hw/ssi-sd.c            |   11 ++++++-----
>>   7 files changed, 125 insertions(+), 60 deletions(-)
>>
>> diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
>> index 3515c3c..1d84d44 100644
>> --- a/hw/milkymist-memcard.c
>> +++ b/hw/milkymist-memcard.c
>> @@ -97,7 +97,7 @@ static void memcard_sd_command(MilkymistMemcardState *s)
>>      req.crc = s->command[5];
>>
>>      s->response[0] = req.cmd;
>> -    s->response_len = sd_do_command(s->card,&req, s->response+1);
>> +    s->response_len = SD_DO_COMMAND(s->card,&req, s->response + 1);
> Does our object model really demand this kind of conversion to all-caps?
> Seems kind of ugly and churny :-(
I think it doesn't, it's just a response to Paolo's request to replace
  SD_GET_CLASS(s->card)->do_command(s->card, &req, s->response + 1) with 
something
not so long.
Also, we can leave functions be for now, and convert them to class 
methods only when somebody actually needs
to override them. Its not encapsulation-righteous though, I don't like this.
Andreas Färber - April 11, 2012, 12:17 p.m.
Am 11.04.2012 13:14, schrieb Igor Mitsyanko:
> 
> 
> On 04/11/2012 02:26 PM, Peter Maydell wrote:
>> On 5 April 2012 16:48, Igor Mitsyanko<i.mitsyanko@samsung.com>  wrote:
>>> A straightforward conversion of SD card implementation to a proper
>>> QEMU object.
>>>
>>> Signed-off-by: Igor Mitsyanko<i.mitsyanko@samsung.com>
>>> ---
>>>   hw/milkymist-memcard.c |   24 ++++++++++++++----------
>>>   hw/omap_mmc.c          |   28 ++++++++++++++++------------
>>>   hw/pl181.c             |   14 ++++++++------
>>>   hw/pxa2xx_mmci.c       |   22 ++++++++++++++--------
>>>   hw/sd.c                |   48
>>> +++++++++++++++++++++++++++++++++++++-----------
>>>   hw/sd.h                |   38 ++++++++++++++++++++++++++++++--------
>>>   hw/ssi-sd.c            |   11 ++++++-----
>>>   7 files changed, 125 insertions(+), 60 deletions(-)
>>>
>>> diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
>>> index 3515c3c..1d84d44 100644
>>> --- a/hw/milkymist-memcard.c
>>> +++ b/hw/milkymist-memcard.c
>>> @@ -97,7 +97,7 @@ static void
>>> memcard_sd_command(MilkymistMemcardState *s)
>>>      req.crc = s->command[5];
>>>
>>>      s->response[0] = req.cmd;
>>> -    s->response_len = sd_do_command(s->card,&req, s->response+1);
>>> +    s->response_len = SD_DO_COMMAND(s->card,&req, s->response + 1);
>> Does our object model really demand this kind of conversion to all-caps?
>> Seems kind of ugly and churny :-(
> I think it doesn't, it's just a response to Paolo's request to replace
>  SD_GET_CLASS(s->card)->do_command(s->card, &req, s->response + 1) with
> something
> not so long.

Just do that as implementation detail in sd_do_command(). No need to
change the call sites then. :)

Andreas
Mitsyanko Igor - April 11, 2012, 12:43 p.m.
On 04/11/2012 04:17 PM, Andreas Färber wrote:
> Am 11.04.2012 13:14, schrieb Igor Mitsyanko:
>>
>> On 04/11/2012 02:26 PM, Peter Maydell wrote:
>>> On 5 April 2012 16:48, Igor Mitsyanko<i.mitsyanko@samsung.com>   wrote:
>>>> A straightforward conversion of SD card implementation to a proper
>>>> QEMU object.
>>>>
>>>> Signed-off-by: Igor Mitsyanko<i.mitsyanko@samsung.com>
>>>> ---
>>>>    hw/milkymist-memcard.c |   24 ++++++++++++++----------
>>>>    hw/omap_mmc.c          |   28 ++++++++++++++++------------
>>>>    hw/pl181.c             |   14 ++++++++------
>>>>    hw/pxa2xx_mmci.c       |   22 ++++++++++++++--------
>>>>    hw/sd.c                |   48
>>>> +++++++++++++++++++++++++++++++++++++-----------
>>>>    hw/sd.h                |   38 ++++++++++++++++++++++++++++++--------
>>>>    hw/ssi-sd.c            |   11 ++++++-----
>>>>    7 files changed, 125 insertions(+), 60 deletions(-)
>>>>
>>>> diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
>>>> index 3515c3c..1d84d44 100644
>>>> --- a/hw/milkymist-memcard.c
>>>> +++ b/hw/milkymist-memcard.c
>>>> @@ -97,7 +97,7 @@ static void
>>>> memcard_sd_command(MilkymistMemcardState *s)
>>>>       req.crc = s->command[5];
>>>>
>>>>       s->response[0] = req.cmd;
>>>> -    s->response_len = sd_do_command(s->card,&req, s->response+1);
>>>> +    s->response_len = SD_DO_COMMAND(s->card,&req, s->response + 1);
>>> Does our object model really demand this kind of conversion to all-caps?
>>> Seems kind of ugly and churny :-(
>> I think it doesn't, it's just a response to Paolo's request to replace
>>   SD_GET_CLASS(s->card)->do_command(s->card,&req, s->response + 1) with
>> something
>> not so long.
> Just do that as implementation detail in sd_do_command(). No need to
> change the call sites then. :)
>
> Andreas
>
Great idea, thanks.

Patch

diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 3515c3c..1d84d44 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -97,7 +97,7 @@  static void memcard_sd_command(MilkymistMemcardState *s)
     req.crc = s->command[5];
 
     s->response[0] = req.cmd;
-    s->response_len = sd_do_command(s->card, &req, s->response+1);
+    s->response_len = SD_DO_COMMAND(s->card, &req, s->response + 1);
     s->response_read_ptr = 0;
 
     if (s->response_len == 16) {
@@ -141,11 +141,12 @@  static uint64_t memcard_read(void *opaque, target_phys_addr_t addr,
         if (!s->enabled) {
             r = 0xffffffff;
         } else {
+            SDClass *sd_class = SD_GET_CLASS(s->card);
             r = 0;
-            r |= sd_read_data(s->card) << 24;
-            r |= sd_read_data(s->card) << 16;
-            r |= sd_read_data(s->card) << 8;
-            r |= sd_read_data(s->card);
+            r |= sd_class->read_data(s->card) << 24;
+            r |= sd_class->read_data(s->card) << 16;
+            r |= sd_class->read_data(s->card) << 8;
+            r |= sd_class->read_data(s->card);
         }
         break;
     case R_CLK2XDIV:
@@ -170,6 +171,7 @@  static void memcard_write(void *opaque, target_phys_addr_t addr, uint64_t value,
                           unsigned size)
 {
     MilkymistMemcardState *s = opaque;
+    SDClass *sd_class;
 
     trace_milkymist_memcard_memory_write(addr, value);
 
@@ -198,10 +200,11 @@  static void memcard_write(void *opaque, target_phys_addr_t addr, uint64_t value,
         if (!s->enabled) {
             break;
         }
-        sd_write_data(s->card, (value >> 24) & 0xff);
-        sd_write_data(s->card, (value >> 16) & 0xff);
-        sd_write_data(s->card, (value >> 8) & 0xff);
-        sd_write_data(s->card, value & 0xff);
+        sd_class = SD_GET_CLASS(s->card);
+        sd_class->write_data(s->card, (value >> 24) & 0xff);
+        sd_class->write_data(s->card, (value >> 16) & 0xff);
+        sd_class->write_data(s->card, (value >> 8) & 0xff);
+        sd_class->write_data(s->card, value & 0xff);
         break;
     case R_ENABLE:
         s->regs[addr] = value;
@@ -249,8 +252,9 @@  static int milkymist_memcard_init(SysBusDevice *dev)
     MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
     DriveInfo *dinfo;
 
+    s->card = SD_CARD(object_new(TYPE_SD_CARD));
     dinfo = drive_get_next(IF_SD);
-    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    SD_INIT(s->card, dinfo ? dinfo->bdrv : NULL, false);
     s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
 
     memory_region_init_io(&s->regs_region, &memcard_mmio_ops, s,
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
index aec0285..15bc1ae 100644
--- a/hw/omap_mmc.c
+++ b/hw/omap_mmc.c
@@ -138,7 +138,7 @@  static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
     request.arg = host->arg;
     request.crc = 0; /* FIXME */
 
-    rsplen = sd_do_command(host->card, &request, response);
+    rsplen = SD_DO_COMMAND(host->card, &request, response);
 
     /* TODO: validate CRCs */
     switch (resptype) {
@@ -219,6 +219,7 @@  static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
 
 static void omap_mmc_transfer(struct omap_mmc_s *host)
 {
+    SDClass *sd_class = SD_GET_CLASS(host->card);
     uint8_t value;
 
     if (!host->transfer)
@@ -229,10 +230,10 @@  static void omap_mmc_transfer(struct omap_mmc_s *host)
             if (host->fifo_len > host->af_level)
                 break;
 
-            value = sd_read_data(host->card);
+            value = sd_class->read_data(host->card);
             host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
             if (-- host->blen_counter) {
-                value = sd_read_data(host->card);
+                value = sd_class->read_data(host->card);
                 host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
                         value << 8;
                 host->blen_counter --;
@@ -244,10 +245,10 @@  static void omap_mmc_transfer(struct omap_mmc_s *host)
                 break;
 
             value = host->fifo[host->fifo_start] & 0xff;
-            sd_write_data(host->card, value);
+            sd_class->write_data(host->card, value);
             if (-- host->blen_counter) {
                 value = host->fifo[host->fifo_start] >> 8;
-                sd_write_data(host->card, value);
+                sd_class->write_data(host->card, value);
                 host->blen_counter --;
             }
 
@@ -592,7 +593,8 @@  struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
     memory_region_add_subregion(sysmem, base, &s->iomem);
 
     /* Instantiate the storage */
-    s->card = sd_init(bd, 0);
+    s->card = SD_CARD(object_new(TYPE_SD_CARD));
+    SD_INIT(s->card, bd, false);
 
     return s;
 }
@@ -617,10 +619,11 @@  struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
     omap_l4_attach(ta, 0, &s->iomem);
 
     /* Instantiate the storage */
-    s->card = sd_init(bd, 0);
+    s->card = SD_CARD(object_new(TYPE_SD_CARD));
+    SD_INIT(s->card, bd, false);
 
     s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
-    sd_set_cb(s->card, NULL, s->cdet);
+    SD_SET_CB(s->card, NULL, s->cdet);
 
     return s;
 }
@@ -628,14 +631,15 @@  struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
 void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
 {
     if (s->cdet) {
-        sd_set_cb(s->card, ro, s->cdet);
+        SD_SET_CB(s->card, ro, s->cdet);
         s->coverswitch = cover;
         qemu_set_irq(cover, s->cdet_state);
-    } else
-        sd_set_cb(s->card, ro, cover);
+    } else {
+        SD_SET_CB(s->card, ro, cover);
+    }
 }
 
 void omap_mmc_enable(struct omap_mmc_s *s, int enable)
 {
-    sd_enable(s->card, enable);
+    SD_ENABLE(s->card, !!enable);
 }
diff --git a/hw/pl181.c b/hw/pl181.c
index 7d91fbb..b2b1ed4 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -171,7 +171,7 @@  static void pl181_send_command(pl181_state *s)
     request.cmd = s->cmd & PL181_CMD_INDEX;
     request.arg = s->cmdarg;
     DPRINTF("Command %d %08x\n", request.cmd, request.arg);
-    rlen = sd_do_command(s->card, &request, response);
+    rlen = SD_DO_COMMAND(s->card, &request, response);
     if (rlen < 0)
         goto error;
     if (s->cmd & PL181_CMD_RESPONSE) {
@@ -209,18 +209,19 @@  error:
 
 static void pl181_fifo_run(pl181_state *s)
 {
+    SDClass *sd_class = SD_GET_CLASS(s->card);
     uint32_t bits;
     uint32_t value = 0;
     int n;
     int is_read;
 
     is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
-    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
+    if (s->datacnt != 0 && (!is_read || sd_class->data_ready(s->card))
             && !s->linux_hack) {
         if (is_read) {
             n = 0;
             while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
-                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+                value |= (uint32_t)sd_class->read_data(s->card) << (n * 8);
                 s->datacnt--;
                 n++;
                 if (n == 4) {
@@ -241,7 +242,7 @@  static void pl181_fifo_run(pl181_state *s)
                 }
                 n--;
                 s->datacnt--;
-                sd_write_data(s->card, value & 0xff);
+                sd_class->write_data(s->card, value & 0xff);
                 value >>= 8;
             }
         }
@@ -469,7 +470,7 @@  static void pl181_reset(DeviceState *d)
     s->mask[1] = 0;
 
     /* We can assume our GPIO outputs have been wired up now */
-    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
+    SD_SET_CB(s->card, s->cardstatus[0], s->cardstatus[1]);
 }
 
 static int pl181_init(SysBusDevice *dev)
@@ -483,7 +484,8 @@  static int pl181_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq[1]);
     qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
     dinfo = drive_get_next(IF_SD);
-    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    s->card = SD_CARD(object_new(TYPE_SD_CARD));
+    SD_INIT(s->card, dinfo ? dinfo->bdrv : NULL, false);
     return 0;
 }
 
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
index b505a4c..a7081b0 100644
--- a/hw/pxa2xx_mmci.c
+++ b/hw/pxa2xx_mmci.c
@@ -117,25 +117,30 @@  static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
 
 static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
 {
-    if (!s->active)
+    SDClass *sd_class = SD_GET_CLASS(s->card);
+
+    if (!s->active) {
         return;
+    }
 
     if (s->cmdat & CMDAT_WR_RD) {
         while (s->bytesleft && s->tx_len) {
-            sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
+            sd_class->write_data(s->card, s->tx_fifo[s->tx_start++]);
             s->tx_start &= 0x1f;
             s->tx_len --;
             s->bytesleft --;
         }
-        if (s->bytesleft)
+        if (s->bytesleft) {
             s->intreq |= INT_TXFIFO_REQ;
-    } else
+        }
+    } else {
         while (s->bytesleft && s->rx_len < 32) {
             s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
-                sd_read_data(s->card);
+                sd_class->read_data(s->card);
             s->bytesleft --;
             s->intreq |= INT_RXFIFO_REQ;
         }
+    }
 
     if (!s->bytesleft) {
         s->active = 0;
@@ -166,7 +171,7 @@  static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
     request.arg = s->arg;
     request.crc = 0;	/* FIXME */
 
-    rsplen = sd_do_command(s->card, &request, response);
+    rsplen = SD_DO_COMMAND(s->card, &request, response);
     s->intreq |= INT_END_CMD;
 
     memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
@@ -538,7 +543,8 @@  PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
     memory_region_add_subregion(sysmem, base, &s->iomem);
 
     /* Instantiate the actual storage */
-    s->card = sd_init(bd, 0);
+    s->card = SD_CARD(object_new(TYPE_SD_CARD));
+    SD_INIT(s->card, bd, false);
 
     register_savevm(NULL, "pxa2xx_mmci", 0, 0,
                     pxa2xx_mmci_save, pxa2xx_mmci_load, s);
@@ -549,5 +555,5 @@  PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
 void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
                 qemu_irq coverswitch)
 {
-    sd_set_cb(s->card, readonly, coverswitch);
+    SD_SET_CB(s->card, readonly, coverswitch);
 }
diff --git a/hw/sd.c b/hw/sd.c
index 6f6be88..58d94ed 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -75,6 +75,8 @@  enum {
 };
 
 struct SDState {
+    Object parent_obj;
+
     uint32_t mode;
     int32_t state;
     uint32_t ocr;
@@ -484,11 +486,8 @@  static const VMStateDescription sd_vmstate = {
    whether card should be in SSI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
    is asserted.  */
-SDState *sd_init(BlockDriverState *bs, bool is_spi)
+static void sd_init(SDState *sd, BlockDriverState *bs, bool is_spi)
 {
-    SDState *sd;
-
-    sd = (SDState *) g_malloc0(sizeof(SDState));
     sd->buf = qemu_blockalign(bs, 512);
     sd->spi = is_spi;
     sd->enable = true;
@@ -498,10 +497,9 @@  SDState *sd_init(BlockDriverState *bs, bool is_spi)
         bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
     }
     vmstate_register(NULL, -1, &sd_vmstate, sd);
-    return sd;
 }
 
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
+static void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
 {
     sd->readonly_cb = readonly;
     sd->inserted_cb = insert;
@@ -1332,7 +1330,7 @@  static int cmd_valid_while_locked(SDState *sd, SDRequest *req)
     return sd_cmd_class[req->cmd] == 0 || sd_cmd_class[req->cmd] == 7;
 }
 
-int sd_do_command(SDState *sd, SDRequest *req,
+static int sd_do_command(SDState *sd, SDRequest *req,
                   uint8_t *response) {
     int last_state;
     sd_rsp_type_t rtype;
@@ -1500,7 +1498,7 @@  static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
 #define APP_READ_BLOCK(a, len)	memset(sd->data, 0xec, len)
 #define APP_WRITE_BLOCK(a, len)
 
-void sd_write_data(SDState *sd, uint8_t value)
+static void sd_write_data(SDState *sd, uint8_t value)
 {
     int i;
 
@@ -1624,7 +1622,7 @@  void sd_write_data(SDState *sd, uint8_t value)
     }
 }
 
-uint8_t sd_read_data(SDState *sd)
+static uint8_t sd_read_data(SDState *sd)
 {
     /* TODO: Append CRCs */
     uint8_t ret;
@@ -1743,12 +1741,40 @@  uint8_t sd_read_data(SDState *sd)
     return ret;
 }
 
-bool sd_data_ready(SDState *sd)
+static bool sd_data_ready(SDState *sd)
 {
     return sd->state == sd_sendingdata_state;
 }
 
-void sd_enable(SDState *sd, bool enable)
+static void sd_enable(SDState *sd, bool enable)
 {
     sd->enable = enable;
 }
+
+static void sd_class_init(ObjectClass *class, void *data)
+{
+    SDClass *k = SD_CLASS(class);
+
+    k->init = sd_init;
+    k->set_cb = sd_set_cb;
+    k->do_command = sd_do_command;
+    k->data_ready = sd_data_ready;
+    k->read_data = sd_read_data;
+    k->write_data = sd_write_data;
+    k->enable = sd_enable;
+}
+
+static TypeInfo sd_type_info = {
+    .name = TYPE_SD_CARD,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(SDState),
+    .class_init = sd_class_init,
+    .class_size = sizeof(SDClass)
+};
+
+static void sd_register_type(void)
+{
+    type_register_static(&sd_type_info);
+}
+
+type_init(sd_register_type)
diff --git a/hw/sd.h b/hw/sd.h
index 4eb9679..d8f0195 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -29,6 +29,9 @@ 
 #ifndef __hw_sd_h
 #define __hw_sd_h		1
 
+#include "qemu-common.h"
+#include "qemu/object.h"
+
 #define OUT_OF_RANGE		(1 << 31)
 #define ADDRESS_ERROR		(1 << 30)
 #define BLOCK_LEN_ERROR		(1 << 29)
@@ -67,13 +70,32 @@  typedef struct {
 
 typedef struct SDState SDState;
 
-SDState *sd_init(BlockDriverState *bs, bool is_spi);
-int sd_do_command(SDState *sd, SDRequest *req,
-                  uint8_t *response);
-void sd_write_data(SDState *sd, uint8_t value);
-uint8_t sd_read_data(SDState *sd);
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
-bool sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, bool enable);
+typedef struct SDClass {
+    ObjectClass parent_class;
+
+    void (*init)(SDState *sd, BlockDriverState *bs, bool is_spi);
+    int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
+    void (*write_data)(SDState *sd, uint8_t value);
+    uint8_t (*read_data)(SDState *sd);
+    void (*set_cb)(SDState *sd, qemu_irq readonly, qemu_irq insert);
+    bool (*data_ready)(SDState *sd);
+    void (*enable)(SDState *sd, bool enable);
+} SDClass;
+
+#define TYPE_SD_CARD            "sd-card"
+#define SD_CARD(obj)            \
+     OBJECT_CHECK(SDState, (obj), TYPE_SD_CARD)
+#define SD_CLASS(klass)         \
+     OBJECT_CLASS_CHECK(SDClass, (klass), TYPE_SD_CARD)
+#define SD_GET_CLASS(obj)       \
+     OBJECT_GET_CLASS(SDClass, (obj), TYPE_SD_CARD)
+
+#define SD_INIT(sd, bdrv, is_spi)   (SD_GET_CLASS(sd)->init(sd, bdrv, is_spi))
+#define SD_DO_COMMAND(sd, req, rsp) (SD_GET_CLASS(sd)->do_command(sd, req, rsp))
+#define SD_WRITE(sd, value)         (SD_GET_CLASS(sd)->write_data(sd, value))
+#define SD_READ(sd)                 (SD_GET_CLASS(sd)->read_data(sd))
+#define SD_SET_CB(sd, ro, ins)      (SD_GET_CLASS(sd)->set_cb(sd, ro, ins))
+#define SD_DATA_READY(sd)           (SD_GET_CLASS(sd)->data_ready(sd))
+#define SD_ENABLE(sd, enbl)         (SD_GET_CLASS(sd)->enable(sd, enbl))
 
 #endif	/* __hw_sd_h */
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index b519bdb..beecc0e 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -94,7 +94,7 @@  static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
             request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
                            | (s->cmdarg[2] << 8) | s->cmdarg[3];
             DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
-            s->arglen = sd_do_command(s->sd, &request, longresp);
+            s->arglen = SD_DO_COMMAND(s->sd, &request, longresp);
             if (s->arglen <= 0) {
                 s->arglen = 1;
                 s->response[0] = 4;
@@ -171,7 +171,7 @@  static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
             DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
             return s->response[s->response_pos++];
         }
-        if (sd_data_ready(s->sd)) {
+        if (SD_DATA_READY(s->sd)) {
             DPRINTF("Data read\n");
             s->mode = SSI_SD_DATA_START;
         } else {
@@ -184,8 +184,8 @@  static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
         s->mode = SSI_SD_DATA_READ;
         return 0xfe;
     case SSI_SD_DATA_READ:
-        val = sd_read_data(s->sd);
-        if (!sd_data_ready(s->sd)) {
+        val = SD_READ(s->sd);
+        if (!SD_DATA_READY(s->sd)) {
             DPRINTF("Data read end\n");
             s->mode = SSI_SD_CMD;
         }
@@ -239,7 +239,8 @@  static int ssi_sd_init(SSISlave *dev)
 
     s->mode = SSI_SD_CMD;
     dinfo = drive_get_next(IF_SD);
-    s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, 1);
+    s->sd = SD_CARD(object_new(TYPE_SD_CARD));
+    SD_INIT(s->sd, dinfo ? dinfo->bdrv : NULL, true);
     register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
     return 0;
 }