libsdhcdrivers: Extract write and read commands

Write and read commands share the same logic with only the command
being the difference thus logic can be extracted.
diff --git a/libsdhcdrivers/src/mmc.c b/libsdhcdrivers/src/mmc.c
index 861fb70..2b1a4a6 100644
--- a/libsdhcdrivers/src/mmc.c
+++ b/libsdhcdrivers/src/mmc.c
@@ -423,29 +423,41 @@
     return 0;
 }
 
-long mmc_block_read(mmc_card_t mmc_card, unsigned long start,
-                    int nblocks, void *vbuf, uintptr_t pbuf, mmc_cb cb, void *token)
+static
+long transfer_data(
+    mmc_card_t mmc_card,
+    unsigned long start,
+    int nblocks,
+    void *vbuf,
+    uintptr_t pbuf,
+    mmc_cb cb,
+    void *token,
+    uint32_t command)
 {
     struct mmc_cmd *cmd;
     uint32_t arg;
     int bs;
     bs = mmc_block_size(mmc_card);
+
     /* Determine command argument */
     if (mmc_card->high_capacity) {
         arg = start;
     } else {
         arg = start * bs;
     }
+
     /* Allocate command structure */
-    cmd = mmc_cmd_new(MMC_READ_SINGLE_BLOCK, arg, MMC_RSP_TYPE_R1);
+    cmd = mmc_cmd_new(command, arg, MMC_RSP_TYPE_R1);
     if (cmd == NULL) {
         return -1;
     }
+
     /* Add a data segment */
     if (mmc_cmd_add_data(cmd, vbuf, pbuf, start, bs, nblocks)) {
         mmc_cmd_destroy(cmd);
         return -1;
     }
+
     /* Send the command */
     if (cb) {
         struct mmc_completion_token *mmc_token;
@@ -469,54 +481,35 @@
     }
 }
 
+long mmc_block_read(mmc_card_t mmc_card, unsigned long start,
+                    int nblocks, void *vbuf, uintptr_t pbuf, mmc_cb cb, void *token)
+{
+    return transfer_data(
+               mmc_card,
+               start,
+               nblocks,
+               vbuf,
+               pbuf,
+               cb,
+               token,
+               MMC_READ_SINGLE_BLOCK);
+}
 
 long mmc_block_write(mmc_card_t mmc_card, unsigned long start, int nblocks,
                      const void *vbuf, uintptr_t pbuf, mmc_cb cb, void *token)
 {
-    struct mmc_cmd *cmd;
-    uint32_t arg;
-    int bs;
-    bs = mmc_block_size(mmc_card);
-    /* Determine command argument */
-    if (mmc_card->high_capacity) {
-        arg = start;
-    } else {
-        arg = start * bs;
-    }
-    /* Allocate command structure */
-    cmd = mmc_cmd_new(MMC_WRITE_BLOCK, arg, MMC_RSP_TYPE_R1);
-    if (cmd == NULL) {
-        return -1;
-    }
-
-    /* Add a data segment */
-    if (mmc_cmd_add_data(cmd, (void *)vbuf, pbuf, start, bs, nblocks)) {
-        mmc_cmd_destroy(cmd);
-        return -1;
-    }
-
-    /* Send the command */
-    if (cb) {
-        struct mmc_completion_token *mmc_token;
-        unsigned long ret;
-        mmc_token = mmc_new_completion_token(mmc_card, cb, token);
-        if (mmc_token == NULL) {
-            mmc_cmd_destroy(cmd);
-            return -1;
-        }
-        ret = host_send_command(mmc_card, cmd, &mmc_blockop_completion_cb,
-                                mmc_token);
-        if (ret) {
-            mmc_completion_token_destroy(mmc_token);
-            mmc_cmd_destroy(cmd);
-        }
-        return ret;
-    } else {
-        unsigned long ret;
-        ret = host_send_command(mmc_card, cmd, NULL, NULL);
-        mmc_cmd_destroy(cmd);
-        return (ret) ? ret : bs * nblocks;
-    }
+    // vbuf's `const` gets dropped during the cast as the underlying layer
+    // accepts only non-const buffer, however it is ok, as we are sending the
+    // write command, what quarantees that the buffer won't be overwritten.
+    return transfer_data(
+               mmc_card,
+               start,
+               nblocks,
+               (void *)vbuf,
+               pbuf,
+               cb,
+               token,
+               MMC_WRITE_BLOCK);
 }
 
 unsigned long long mmc_card_capacity(mmc_card_t mmc_card)