You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by je...@apache.org on 2026/06/26 07:50:26 UTC

(mynewt-core) branch master updated (eb3d397bc -> 48df2deeb)

This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git


    from eb3d397bc ci: add explicit least-privilege permissions to CI workflows
     new d0a74e309 fs/disks: Rework disk interface
     new a2dbdfdba fs: Introduce file system entity
     new 668ddf7dd fs/nffs: Use mount points
     new c7b3066d7 fs/fs: Add mount cli command
     new 9470a663c fs/fatfs: Rework to use file system api
     new 703229e95 fs/littlefs: Use mount points
     new 4ab74a691 util: Add bit_set
     new 48df2deeb drivers/mmc: Rework to use change disk api

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 fs/disk/include/disk/disk.h               | 204 ++++++-
 fs/disk/pkg.yml                           |   5 +-
 fs/disk/src/disk.c                        | 141 +----
 fs/fatfs/pkg.yml                          |   8 +-
 fs/fatfs/src/mynewt_glue.c                | 415 ++++++--------
 fs/fatfs/syscfg.yml                       |   6 +
 fs/fs/include/fs/fs_if.h                  |  78 ++-
 fs/fs/pkg.yml                             |   3 -
 fs/fs/src/fs_cli.c                        |  18 +
 fs/fs/src/fs_dirent.c                     |  19 +-
 fs/fs/src/fs_file.c                       |  72 ++-
 fs/fs/src/fs_mkdir.c                      |  25 +-
 fs/fs/src/fs_mount.c                      | 134 +++--
 fs/fs/src/fs_priv.h                       |   5 +-
 fs/fs/syscfg.yml                          |   7 +
 fs/littlefs/src/littlefs_glue.c           |  34 +-
 fs/nffs/src/nffs.c                        |  25 +-
 hw/drivers/mmc/include/mmc/mmc.h          |  76 +--
 hw/drivers/mmc/pkg.yml                    |   2 +
 hw/drivers/mmc/src/mmc.c                  | 912 +++++++++++++++++-------------
 hw/drivers/mmc/syscfg.yml                 |  36 +-
 hw/util/bit_set/include/bit_set/bit_set.h | 130 +++++
 hw/{drivers/led => util/bit_set}/pkg.yml  |   4 +-
 hw/util/bit_set/src/bit_set.c             | 112 ++++
 24 files changed, 1539 insertions(+), 932 deletions(-)
 create mode 100644 hw/util/bit_set/include/bit_set/bit_set.h
 copy hw/{drivers/led => util/bit_set}/pkg.yml (93%)
 create mode 100644 hw/util/bit_set/src/bit_set.c


(mynewt-core) 03/08: fs/nffs: Use mount points

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 668ddf7ddade4664882a21ee1f2f9354e8894d97
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Sat Jun 21 21:47:59 2025 +0200

    fs/nffs: Use mount points
    
    This updates nffs to use fs_mount instead
    of fs_register.
    
    Signed-off-by: Jerzy Kasenberg <je...@apache.org>
---
 fs/nffs/src/nffs.c | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/fs/nffs/src/nffs.c b/fs/nffs/src/nffs.c
index 1dc9c778f..5315f9354 100644
--- a/fs/nffs/src/nffs.c
+++ b/fs/nffs/src/nffs.c
@@ -30,7 +30,6 @@
 #include "nffs_priv.h"
 #include "nffs/nffs.h"
 #include "fs/fs_if.h"
-#include "disk/disk.h"
 
 struct nffs_area *nffs_areas;
 uint8_t nffs_num_areas;
@@ -98,8 +97,11 @@ struct fs_ops nffs_ops = {
 
     .f_dirent_name = nffs_dirent_name,
     .f_dirent_is_dir = nffs_dirent_is_dir,
+};
 
-    .f_name = "nffs"
+const file_system_t nffs_fs0 = {
+    .ops = &nffs_ops,
+    .name = "nffs",
 };
 
 STATS_SECT_DECL(nffs_stats) nffs_stats;
@@ -190,7 +192,6 @@ nffs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file)
 {
     int rc;
     struct nffs_file *out_file;
-    char *filepath = NULL;
 
     nffs_lock();
 
@@ -199,17 +200,12 @@ nffs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file)
         goto done;
     }
 
-    filepath = disk_filepath_from_path(path);
-
-    rc = nffs_file_open(&out_file, filepath, access_flags);
+    rc = nffs_file_open(&out_file, path, access_flags);
     if (rc != 0) {
         goto done;
     }
     *out_fs_file = (struct fs_file *)out_file;
 done:
-    if (filepath) {
-        free(filepath);
-    }
     nffs_unlock();
     if (rc != 0) {
         *out_fs_file = NULL;
@@ -512,7 +508,6 @@ nffs_opendir(const char *path, struct fs_dir **out_fs_dir)
 {
     int rc;
     struct nffs_dir **out_dir = (struct nffs_dir **)out_fs_dir;
-    char *filepath = NULL;
 
     nffs_lock();
 
@@ -521,14 +516,9 @@ nffs_opendir(const char *path, struct fs_dir **out_fs_dir)
         goto done;
     }
 
-    filepath = disk_filepath_from_path(path);
-
-    rc = nffs_dir_open(filepath, out_dir);
+    rc = nffs_dir_open(path, out_dir);
 
 done:
-    if (filepath) {
-        free(filepath);
-    }
     nffs_unlock();
     if (rc != 0) {
         *out_dir = NULL;
@@ -764,7 +754,8 @@ nffs_init(void)
         return rc;
     }
 
-    fs_register(&nffs_ops);
+    fs_mount(&nffs_fs0, "nffs:");
+
     return 0;
 }
 


(mynewt-core) 07/08: util: Add bit_set

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 4ab74a6915cf5c79bf6092263b75fb4a8b450c68
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Thu Jun 25 15:09:24 2026 +0200

    util: Add bit_set
    
    Simple API to work with bit set.
    
    Signed-off-by: Jerzy Kasenberg <je...@codecoup.pl>
---
 hw/util/bit_set/include/bit_set/bit_set.h | 130 ++++++++++++++++++++++++++++++
 hw/util/bit_set/pkg.yml                   |  24 ++++++
 hw/util/bit_set/src/bit_set.c             | 112 +++++++++++++++++++++++++
 3 files changed, 266 insertions(+)

diff --git a/hw/util/bit_set/include/bit_set/bit_set.h b/hw/util/bit_set/include/bit_set/bit_set.h
new file mode 100644
index 000000000..2f343c871
--- /dev/null
+++ b/hw/util/bit_set/include/bit_set/bit_set.h
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _UTIL_BIT_SET_H_
+#define _UTIL_BIT_SET_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <os/endian.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Set bit from other bit set
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param start_bit - first bit to set
+ * @param bit_count - number of bits to set
+ * @param src_bits - source bits (starting from bit 0)
+ */
+void bit_set_set_bits(void *bit_set, int start_bit, int bit_count, const void *src_bits);
+
+/**
+ * Get bits from bit set
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param start_bit - first bit to extract
+ * @param bit_count - number of bits to extract
+ * @param dst_bits - buffer for extracted bits (little endian buffer)
+ */
+void bit_set_get_bits(const void *bit_set, int start_bit, int bit_count, void *dst_bits);
+
+/**
+ * Get single bit value from bit set in little endian order
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param bit_num - bit to get
+ * @return value of bit_num bit
+ */
+uint32_t bit_set_get_bit(const void *bit_set, int bit_num);
+
+/**
+ * Set bit in bit set
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param bit_num - bit to set value
+ * @param val - 0 or 1 value to set
+ */
+void bit_set_set_bit(void *bit_set, int bit_num, uint32_t val);
+
+/**
+ * Set bit in bit set
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param bit_num - bit to set value
+ * @return bit value after flip
+ */
+uint32_t bit_set_flip_bit(void *bit_set, int bit_num);
+
+/**
+ * Reverse bytes in bit set
+ * This can be useful if original buffer contains bytes in bit endian order
+ *
+ * @param bit_set - bit set to revers order
+ * @param bit_count - number of bits in bit set
+ */
+static inline void
+bit_set_reverse(void *bit_set, int bit_count)
+{
+    swap_in_place(bit_set, ((bit_count + 7) >> 3));
+}
+
+/**
+ * Get 32 bit value from bit set starting from given bit
+ * This function is wrapper to ease extraction of bit fields
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param start_bit - first bit to extract
+ * @param bit_count - number of bits to extract
+ * @return 32 bit value in host order
+ */
+static inline uint32_t
+bit_set_get_uint32(const void *bit_set, int start_bit, int bit_count)
+{
+    uint32_t val = 0;
+
+    bit_set_get_bits(bit_set, start_bit, bit_count, &val);
+
+    return le32toh(val);
+}
+
+/**
+ * Set number of bit in bit set from host order integer value
+ *
+ * @param bit_set - pointer to first byte of a bit set
+ * @param start_bit - first bit to set
+ * @param bit_count - number of bits to set
+ * @param val - host order val to set in bit field
+ */
+static inline void
+bit_set_set_uint32(void *bit_set, int start_bit, int bit_count, uint32_t val)
+{
+    val = htole32(val);
+
+    bit_set_set_bits(bit_set, start_bit, bit_count, &val);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/util/bit_set/pkg.yml b/hw/util/bit_set/pkg.yml
new file mode 100644
index 000000000..f2d960e8c
--- /dev/null
+++ b/hw/util/bit_set/pkg.yml
@@ -0,0 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: util/bit_set
+pkg.description: Bit manipulation package
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
diff --git a/hw/util/bit_set/src/bit_set.c b/hw/util/bit_set/src/bit_set.c
new file mode 100644
index 000000000..91e10c0bb
--- /dev/null
+++ b/hw/util/bit_set/src/bit_set.c
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANYÄ„
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdint.h>
+#include <bit_set/bit_set.h>
+#include <os/endian.h>
+#include <os/os.h>
+
+void
+bit_set_set_bits(void *bit_set, int start_bit, int bit_count, const void *src_bits)
+{
+    const uint8_t *src_bytes = (uint8_t *)src_bits;
+    uint32_t bits = *src_bytes++;
+    int start_byte = start_bit >> 3;
+
+    uint8_t *bytes = start_byte + (uint8_t *)bit_set;
+    start_bit -= start_byte << 3;
+    int src_bit_offset = start_bit;
+
+    while (bit_count > 0) {
+        int n = min(bit_count, 8);
+        uint8_t mask = ((1 << n) - 1) << start_bit;
+        uint8_t b = (*bytes & ~mask) | ((bits << start_bit) & mask);
+        *bytes++ = b;
+        bit_count -= 8 - start_bit;
+        bits >>= 8 - start_bit;
+        start_bit = 0;
+        bits |= (*src_bytes++) << src_bit_offset;
+    }
+}
+
+void
+bit_set_get_bits(const void *bit_set, int start_bit, int bit_count, void *dst_bits)
+{
+    uint8_t *dst_bytes = (uint8_t *)dst_bits;
+    int start_byte = start_bit >> 3;
+    const uint8_t *bytes = start_byte + (const uint8_t *)bit_set;
+    start_bit -= start_byte << 3;
+    uint32_t bits = 0;
+    uint32_t dst_bit_offset = 0;
+    int dst_bit_count = 0;
+
+    while (dst_bit_count > 0 || bit_count > 0) {
+        if (bit_count) {
+            int n = min(bit_count, 8 - start_bit);
+            bits |= ((*bytes++) >> start_bit) << dst_bit_offset;
+            if (start_bit) {
+                dst_bit_offset = 8 - start_bit;
+                start_bit = 0;
+            }
+            dst_bit_count += n;
+            bit_count -= n;
+        }
+        if (bit_count <= 0 || dst_bit_count >= 8) {
+            if (dst_bit_count < 8) {
+                uint8_t mask = (1 << dst_bit_count) - 1;
+                bits &= (1 << dst_bit_count) - 1;
+                *dst_bytes = (*dst_bytes & ~mask) | (bits & mask);
+            } else {
+                *dst_bytes++ = (uint8_t)bits;
+            }
+            dst_bit_count -= 8;
+            bits >>= 8;
+        }
+    }
+}
+
+uint32_t
+bit_set_get_bit(const void *bit_set, int bit_num)
+{
+    uint8_t b;
+
+    bit_set_get_bits(bit_set, bit_num, 1, &b);
+
+    return b;
+}
+
+void
+bit_set_set_bit(void *bit_set, int bit_num, uint32_t val)
+{
+    uint8_t b = val & 1;
+
+    bit_set_set_bits(bit_set, bit_num, 1, &b);
+}
+
+uint32_t
+bit_set_flip_bit(void *bit_set, int bit_num)
+{
+    uint8_t b;
+
+    bit_set_get_bits(bit_set, bit_num, 1, &b);
+    b ^= 1;
+    bit_set_set_bits(bit_set, bit_num, 1, &b);
+
+    return b;
+}


(mynewt-core) 04/08: fs/fs: Add mount cli command

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit c7b3066d78cf68282b53225f38e701934a4e0165
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Sat Jun 21 22:17:29 2025 +0200

    fs/fs: Add mount cli command
    
    This adds command to show mounted file systems
    
    Signed-off-by: Jerzy Kasenberg <je...@apache.org>
---
 fs/fs/src/fs_cli.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/fs/fs/src/fs_cli.c b/fs/fs/src/fs_cli.c
index 10412d2bc..45a8d5e82 100644
--- a/fs/fs/src/fs_cli.c
+++ b/fs/fs/src/fs_cli.c
@@ -28,6 +28,7 @@
 #include <console/console.h>
 
 #include "fs/fs.h"
+#include "fs/fs_if.h"
 
 static void
 fs_ls_file(const char *name, struct fs_file *file)
@@ -160,6 +161,22 @@ out:
     return 0;
 }
 
+extern struct mount_point mount_points[];
+
+static int
+fs_mount_cmd(int argc, char **argv)
+{
+    console_printf("mount points:\n");
+    for (int i = 0; i < MYNEWT_VAL_FS_MAX_MOUNT_POINTS; ++i) {
+        if (mount_points[i].fs) {
+            console_printf("%s %s\n", mount_points[i].mount_point,
+                           mount_points[i].fs->name);
+        }
+    }
+
+    return 0;
+}
+
 static int
 fs_cat_cmd(int argc, char **argv)
 {
@@ -225,5 +242,6 @@ MAKE_SHELL_CMD(rm, fs_rm_cmd, NULL)
 MAKE_SHELL_CMD(mkdir, fs_mkdir_cmd, NULL)
 MAKE_SHELL_CMD(mv, fs_mv_cmd, NULL)
 MAKE_SHELL_CMD(cat, fs_cat_cmd, NULL)
+MAKE_SHELL_CMD(mount, fs_mount_cmd, NULL)
 
 #endif /* MYNEWT_VAL(FS_CLI) */


(mynewt-core) 01/08: fs/disks: Rework disk interface

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit d0a74e3097ad30171b7d3a1454955db7d087b3aa
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Sat Jun 21 10:33:03 2025 +0200

    fs/disks: Rework disk interface
    
    Disk interface tightly coupled to file system
    and could not be used for exposing disk to something
    else then code in fs/fs.
    
    With this change new disk_listener interface allows
    code to be informed about disks being inserted
    and removed.
    
    Listeners in turn can mount file systems from disk
    or for example expose disk to USB host via MSC.
    
    Signed-off-by: Jerzy Kasenberg <je...@apache.org>
---
 fs/disk/include/disk/disk.h | 204 +++++++++++++++++++++++++++++++++++++++++---
 fs/disk/pkg.yml             |   5 +-
 fs/disk/src/disk.c          | 141 +++++-------------------------
 3 files changed, 219 insertions(+), 131 deletions(-)

diff --git a/fs/disk/include/disk/disk.h b/fs/disk/include/disk/disk.h
index cf2849629..514e6f330 100644
--- a/fs/disk/include/disk/disk.h
+++ b/fs/disk/include/disk/disk.h
@@ -22,7 +22,8 @@
 
 #include <stddef.h>
 #include <inttypes.h>
-#include "os/mynewt.h"
+#include <os/mynewt.h>
+#include <os/link_tables.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -35,19 +36,200 @@ extern "C" {
 #define DISK_EOS          4  /* OS error */
 #define DISK_EUNINIT      5  /* File system not initialized */
 
-struct disk_ops {
-    int (*read)(uint8_t, uint32_t, void *, uint32_t);
-    int (*write)(uint8_t, uint32_t, const void *, uint32_t);
-    int (*ioctl)(uint8_t, uint32_t, void *);
+typedef struct disk disk_t;
+typedef struct disk_info disk_info_t;
+typedef struct disk_listener disk_listener_t;
 
-    SLIST_ENTRY(disk_ops) sc_next;
+/**
+ * Disk information
+ */
+struct disk_info {
+    /* Disk name (information only) */
+    const char *name;
+    /* Disk block (sector) count */
+    uint32_t block_count;
+    /* Block size (usually 512) */
+    uint16_t block_size;
+    /* Set to 1 if disk is present */
+    uint16_t present : 1;
+};
+
+typedef struct disk_ops {
+    /** Get basic information about disk
+     *
+     * @param disk - disk to query
+     * @param info - disk information to fill
+     * @return 0 on success, SYS_EINVAL if arguments are incorrect
+     */
+    int (*get_info)(const struct disk *disk, struct disk_info *info);
+
+    /**
+     * Inform driver that disk was just removed
+     * @param disk - disk that was ejected
+     * @return 0 on success, SYS_EINVAL if arguments are incorrect
+     */
+    int (*eject)(struct disk *disk);
+    /**
+     * Read disk block
+     * @param disk - dist to read from
+     * @param lba - block to read
+     * @param buf - buffer for data
+     * @param block_count - number for blocks to read
+     * @return 0 on success
+     */
+    int (*read)(struct disk *disk, uint32_t lba, void *buf, uint32_t block_count);
+    /**
+     * Write disk block
+     * @param disk - dist to write to
+     * @param lba - block to write to
+     * @param buf - data buffer
+     * @param block_count - number of blocks to write
+     * @return 0 on success
+     */
+    int (*write)(struct disk *disk, uint32_t lba, const void *buf, uint32_t block_count);
+} disk_ops_t;
+
+/* Disk listener operations */
+typedef struct disk_listener_ops {
+    /* New disk was inserted to driver and could be mounter */
+    int (*disk_added)(struct disk_listener *listener, struct disk *disk);
+    /* Disk was ejected and should be unmounted */
+    int (*disk_removed)(struct disk_listener *listener, struct disk *disk);
+} disk_listener_ops_t;
+
+/* Disk listener */
+struct disk_listener {
+    const disk_listener_ops_t *ops;
 };
 
-int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops);
-struct disk_ops *disk_ops_for(const char *disk_name);
-char *disk_fs_for(const char *disk_name);
-char *disk_name_from_path(const char *path);
-char *disk_filepath_from_path(const char *path);
+/* Base for disks */
+struct disk {
+    const disk_ops_t *ops;
+};
+
+/**
+ * Function called when disk was inserted into a driver
+ * and system could mount it or otherwise be aware that new
+ * disk could be used
+ *
+ * @param disk - disk that was inserted
+ *
+ * @return 0 - for success
+ */
+int mn_disk_inserted(disk_t *disk);
+
+/**
+ * Function called when disk was removed, if disk was
+ * mounted it file system can be unmounted. If disk
+ * was present to MSC it can no longer be advertised
+ * as present.
+ *
+ * @param disk - disk that was remove from driver
+ *
+ * @return 0 -for success
+ */
+int mn_disk_ejected(disk_t *disk);
+
+/**
+ * Function return 1 if disk is present
+ *
+ * @param disk - disk to check for presence
+ * @return 1 - disk is present, 0 - disk is not present
+ */
+static inline int
+disk_present(disk_t *disk)
+{
+    disk_info_t di;
+    disk->ops->get_info(disk, &di);
+
+    return di.present;
+}
+
+/**
+ * Get disk information
+ * Disk information consist of size information
+ *
+ * @param disk - disk to get information from
+ * @param di - pointer to data to received disk information
+ *
+ * @return 0 - for success
+ */
+static inline int
+mn_disk_info_get(disk_t *disk, disk_info_t *di)
+{
+    return disk->ops->get_info(disk, di);
+}
+
+/**
+ * Read sector(s) from disk
+ *
+ * @param disk - disk to read data from
+ * @param lba - sector number
+ * @param buf - buffer to be filled with data from disk
+ * @param block_count - number of sectors to read
+ * @return 0 - for success
+ */
+static inline int
+mn_disk_read(disk_t *disk, uint32_t lba, void *buf, uint32_t block_count)
+{
+    return disk->ops->read(disk, lba, buf, block_count);
+}
+
+/**
+ * Write sector(s) to disk
+ *
+ * @param disk - disk to write to
+ * @param lba - first sector to write to
+ * @param buf - buffer with data
+ * @param block_count - number of sectors to write
+ * @return 0 - for success
+ */
+static inline int
+mn_disk_write(disk_t *disk, uint32_t lba, const void *buf, uint32_t block_count)
+{
+    return disk->ops->write(disk, lba, buf, block_count);
+}
+
+/**
+ * Eject disk
+ *
+ * Calling this function will result in calling disk listeners about
+ * disk being removed via disk_removed(). This may result in file
+ * system being unmounted.
+ *
+ * @param disk - disk to eject
+ * @return 0 - for success
+ */
+static inline int
+mn_disk_eject(disk_t *disk)
+{
+    return disk->ops->eject(disk);
+}
+
+/**
+ * Link time table to hold all available disk listeners
+ * that will be informed when disk is available and
+ * can be mounted or used in other ways.
+ */
+LINK_TABLE(disk_listener_t *, disk_listeners)
+
+/**
+ * @brief Macros to put disk_listener in link table
+ *
+ * i.e.
+ * // Define disk_listener_t structure
+ * disk_listener_t mounter = {
+ *    .opt = &mounter_ops,
+ * };
+ *
+ * DISK_LISTENER(mounter_entry, mounter)
+ *
+ * @param listener_entry - new pointer variable name that will be put in
+ *                         disk_listeners table
+ * @param listener - object of type disk_listener_t
+ */
+#define DISK_LISTENER(listener_entry, listener)                               \
+    LINK_TABLE_ELEMENT(disk_listeners, listener_entry) = &listener;
 
 #ifdef __cplusplus
 }
diff --git a/fs/disk/pkg.yml b/fs/disk/pkg.yml
index 52a0f7f11..1157f15e9 100644
--- a/fs/disk/pkg.yml
+++ b/fs/disk/pkg.yml
@@ -18,10 +18,13 @@
 #
 
 pkg.name: fs/disk
-pkg.description: Disk management layer to glue filesystems to disk devices.
+pkg.description: Disk management layer to disk devices.
 pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
 pkg.homepage: "http://mynewt.apache.org/"
 pkg.keywords:
 
 pkg.deps:
     - "@apache-mynewt-core/kernel/os"
+
+pkg.link_tables:
+    - disk_listeners
diff --git a/fs/disk/src/disk.c b/fs/disk/src/disk.c
index 93a2741fd..d84ca22b4 100644
--- a/fs/disk/src/disk.c
+++ b/fs/disk/src/disk.c
@@ -17,135 +17,38 @@
  * under the License.
  */
 
-#include <stdlib.h>
-#include <string.h>
-#include "os/mynewt.h"
+#include <inttypes.h>
+#include <os/mynewt.h>
+#include <os/link_tables.h>
 #include <disk/disk.h>
 
-struct disk_info {
-    const char *disk_name;
-    const char *fs_name;
-    struct disk_ops *dops;
+#define DISK_EOK     0 /* Success */
+#define DISK_EHW     1 /* Error accessing storage medium */
+#define DISK_ENOMEM  2 /* Insufficient memory */
+#define DISK_ENOENT  3 /* No such file or directory */
+#define DISK_EOS     4 /* OS error */
+#define DISK_EUNINIT 5 /* File system not initialized */
 
-    SLIST_ENTRY(disk_info) sc_next;
-};
-
-static SLIST_HEAD(, disk_info) disks = SLIST_HEAD_INITIALIZER();
-
-/**
- *
- */
-int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops)
+int
+mn_disk_inserted(disk_t *disk)
 {
-    struct disk_info *info = NULL;
-    struct disk_info *sc;
-
-    SLIST_FOREACH(sc, &disks, sc_next) {
-        if (strcmp(sc->disk_name, disk_name) == 0) {
-            return DISK_ENOENT;
-        }
-    }
+    int count = LINK_TABLE_SIZE(disk_listeners);
 
-    info = malloc(sizeof(struct disk_info));
-    if (!info) {
-        return DISK_ENOMEM;
+    for (int i = 0; i < count; ++i) {
+        disk_listener_t *listener = disk_listeners[i];
+        listener->ops->disk_added(listener, disk);
     }
-
-    info->disk_name = disk_name;
-    info->fs_name = fs_name;
-    info->dops = dops;
-
-    SLIST_INSERT_HEAD(&disks, info, sc_next);
-
     return 0;
 }
 
-struct disk_ops *
-disk_ops_for(const char *disk_name)
+int
+mn_disk_ejected(disk_t *disk)
 {
-    struct disk_info *sc;
+    int count = LINK_TABLE_SIZE(disk_listeners);
 
-    if (disk_name) {
-        SLIST_FOREACH(sc, &disks, sc_next) {
-            if (strcmp(sc->disk_name, disk_name) == 0) {
-                return sc->dops;
-            }
-        }
+    for (int i = 0; i < count; ++i) {
+        disk_listener_t *listener = disk_listeners[i];
+        listener->ops->disk_removed(listener, disk);
     }
-
-    return NULL;
-}
-
-char *
-disk_fs_for(const char *disk_name)
-{
-    struct disk_info *sc;
-
-    if (disk_name) {
-        SLIST_FOREACH(sc, &disks, sc_next) {
-            if (strcmp(sc->disk_name, disk_name) == 0) {
-                return ((char *) sc->fs_name);
-            }
-        }
-    }
-
-    return NULL;
-}
-
-char *
-disk_name_from_path(const char *path)
-{
-    char *colon;
-    uint8_t len;
-    char *disk;
-
-    colon = (char *) path;
-    while (*colon && *colon != ':') {
-        colon++;
-    }
-
-    if (*colon != ':') {
-        return NULL;
-    }
-
-    len = colon - path;
-    disk = malloc(len + 1);
-    if (!disk) {
-        return NULL;
-    }
-    memcpy(disk, path, len);
-    disk[len] = '\0';
-
-    return disk;
-}
-
-/**
- * @brief Returns the path with the disk prefix removed (if found)
- *
- * Paths should be given in the form disk<number>:/path. This routine
- * will parse and return only the path, removing the disk information.
- */
-char *
-disk_filepath_from_path(const char *path)
-{
-    char *colon;
-    char *filepath;
-    size_t len;
-
-    colon = (char *) path;
-    while (*colon && *colon != ':') {
-        colon++;
-    }
-
-    if (*colon != ':') {
-        filepath = strdup(path);
-    } else {
-        colon++;
-        len = strlen(colon);
-        filepath = malloc(len + 1);
-        memcpy(filepath, colon, len);
-        filepath[len] = '\0';
-    }
-
-    return filepath;
+    return 0;
 }


(mynewt-core) 06/08: fs/littlefs: Use mount points

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 703229e955c0acb637f09b0409b78a5635480a1a
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Thu Jun 25 14:56:21 2026 +0200

    fs/littlefs: Use mount points
    
    This updates littlefs to use fs_mount
    
    Signed-off-by: Jerzy Kasenberg <je...@codecoup.pl>
---
 fs/littlefs/src/littlefs_glue.c | 34 +++++++++++++++++++++++++++++-----
 1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/fs/littlefs/src/littlefs_glue.c b/fs/littlefs/src/littlefs_glue.c
index de8b4ad8f..b7b90fed4 100644
--- a/fs/littlefs/src/littlefs_glue.c
+++ b/fs/littlefs/src/littlefs_glue.c
@@ -60,6 +60,8 @@ static int littlefs_closedir(struct fs_dir *dir);
 static int littlefs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len,
                                 char *out_name, uint8_t *out_name_len);
 static int littlefs_dirent_is_dir(const struct fs_dirent *fs_dirent);
+static int _littlefs_mount(const file_system_t *fs);
+static int _littlefs_umount(const file_system_t *fs);
 
 struct littlefs_file {
     struct fs_ops *fops;
@@ -101,7 +103,8 @@ static struct fs_ops littlefs_ops = {
     .f_dirent_name = littlefs_dirent_name,
     .f_dirent_is_dir = littlefs_dirent_is_dir,
 
-    .f_name = "littlefs"
+    .f_mount = _littlefs_mount,
+    .f_umount = _littlefs_umount,
 };
 
 /* Min block size equired by littlefs implementation */
@@ -750,6 +753,22 @@ littlefs_mount(void)
     return FS_EOK;
 }
 
+static int
+_littlefs_mount(const file_system_t *fs)
+{
+    (void)fs;
+
+    return littlefs_mount();
+}
+
+static int
+_littlefs_umount(const file_system_t *fs)
+{
+    (void)fs;
+
+    return lfs_unmount(&g_littlefs);
+}
+
 int
 littlefs_init(void)
 {
@@ -803,6 +822,11 @@ littlefs_init(void)
     return FS_EOK;
 }
 
+static const file_system_t littlefs_fs0 = {
+    .ops = &littlefs_ops,
+    .name = "littlefs"
+};
+
 void
 littlefs_sysinit(void)
 {
@@ -813,8 +837,8 @@ littlefs_sysinit(void)
     rc = littlefs_init();
     SYSINIT_PANIC_ASSERT(rc == 0);
 
-#if MYNEWT_VAL(LITTLEFS_AUTO_MOUNT)
-    rc = littlefs_mount();
-    SYSINIT_PANIC_ASSERT(rc == 0);
-#endif
+    if (MYNEWT_VAL(LITTLEFS_AUTO_MOUNT)) {
+        rc = fs_mount(&littlefs_fs0, "lfs0:");
+        SYSINIT_PANIC_ASSERT(rc == 0);
+    }
 }


(mynewt-core) 02/08: fs: Introduce file system entity

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit a2dbdfdba69159ebe8c02e17ef89a3bde720aae5
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Sat Jun 21 10:50:26 2025 +0200

    fs: Introduce file system entity
    
    File system was represented by fs_ops that consisted of
    bunch of file system functions, name, and pointer to
    link file system ops in chain.
    
    Most of the date was constant and there is was no reason
    to waste RAM for callback pointer.
    
    This introduce file_system object that has ops but
    can be extended to hold file system specific data.
    
    Same file system ops can be used for more then one file
    system.
    File system can be mounted and that what littlefs and other
    file systems will.
    
    This change mostly changes filesystem_ops to const in most
    places.
    
    Signed-off-by: Jerzy Kasenberg <je...@apache.org>
---
 fs/fs/include/fs/fs_if.h |  78 +++++++++++++++++++++++----
 fs/fs/pkg.yml            |   3 --
 fs/fs/src/fs_dirent.c    |  19 ++++---
 fs/fs/src/fs_file.c      |  72 +++++++++++++------------
 fs/fs/src/fs_mkdir.c     |  25 ++++++---
 fs/fs/src/fs_mount.c     | 134 +++++++++++++++++++++++++++++++++++------------
 fs/fs/src/fs_priv.h      |   5 +-
 fs/fs/syscfg.yml         |   7 +++
 8 files changed, 242 insertions(+), 101 deletions(-)

diff --git a/fs/fs/include/fs/fs_if.h b/fs/fs/include/fs/fs_if.h
index 567561f21..4dfa806de 100644
--- a/fs/fs/include/fs/fs_if.h
+++ b/fs/fs/include/fs/fs_if.h
@@ -26,6 +26,16 @@ extern "C" {
 
 #include "os/mynewt.h"
 
+typedef struct file_system {
+    const struct fs_ops *ops;
+    const char *name;
+} file_system_t;
+
+struct mount_point {
+    const char *mount_point;
+    const file_system_t *fs;
+};
+
 /*
  * Common interface filesystem(s) provide.
  */
@@ -53,10 +63,8 @@ struct fs_ops {
     int (*f_dirent_name)(const struct fs_dirent *dirent, size_t max_len,
       char *out_name, uint8_t *out_name_len);
     int (*f_dirent_is_dir)(const struct fs_dirent *dirent);
-
-    const char *f_name;
-
-    SLIST_ENTRY(fs_ops) sc_next;
+    int (*f_mount)(const file_system_t *fs);
+    int (*f_umount)(const file_system_t *fs);
 };
 
 struct fops_container {
@@ -78,18 +86,68 @@ int fs_register(struct fs_ops *fops);
  *
  * @return fops if there's only one registered filesystem, NULL otherwise.
  */
-struct fs_ops *fs_ops_try_unique(void);
+const struct fs_ops *fs_ops_try_unique(void);
+
+const struct fs_ops *fs_ops_from_container(struct fops_container *container);
+
+/**
+ * Mount file system
+ *
+ * @param fs - file system to mount
+ * @param path - path to mount i.e. 0:, nffs:
+ * @return 0 on success
+ */
+int fs_mount(const file_system_t *fs, const char *path);
+
+/**
+ * Unmount file system by mount point
+ *
+ * @param mount_point - mount point to unmount i.e. 0:, nffs:
+ * @return 0 on success
+ */
+const file_system_t *fs_unmount_mount_point(const char *mount_point);
+
+/**
+ * Unmount file system
+ *
+ * @param fs - mounted file system to unmount
+ * @return 0 on success
+ */
+int fs_unmount_file_system(const file_system_t *fs);
 
 /**
- * Retrieve a filesystem's operations table
+ * Get file system mount point path
+ *
+ * For given path it will return mount point and file system
+ * i.e.:
+ * For 0:/DIREC/FIL.TXT function will return "0:" and fs
+ * will be filled with pointer to valid file_system_t structure.
  *
- * @param name Name of the filesystem to retrieve fs_ops for
+ * @param path - file or directory name
+ * @param fs - on success file system
+ * @return file system mount point string
+ */
+const char *file_system_path(const char *path, const file_system_t **fs);
+
+/**
+ * Return the only file system mounted
  *
- * @return valid pointer on success, NULL on failure
+ * It there is only one file system mounted it will be returned by this
+ * function. If two file system were mounted funciton will return NULL.
+ * @return non-NULL if exactly one file system is mounted, otherwise NULL
  */
-struct fs_ops *fs_ops_for(const char *name);
+const file_system_t *get_only_file_system(void);
 
-struct fs_ops *fs_ops_from_container(struct fops_container *container);
+/**
+ * Get file system and file system mount point
+ *
+ * Usually
+ * @param path - file system path
+ * @param fs - file system for path
+ * @param fs_path - mount point (usually prefix of file path)
+ */
+void get_file_system_path(const char *path, const file_system_t **fs,
+                          const char **fs_path);
 
 #ifdef __cplusplus
 }
diff --git a/fs/fs/pkg.yml b/fs/fs/pkg.yml
index 10c68746e..fc3e1eeaa 100644
--- a/fs/fs/pkg.yml
+++ b/fs/fs/pkg.yml
@@ -26,9 +26,6 @@ pkg.keywords:
     - filesystem
     - ffs
 
-pkg.deps:
-    - "@apache-mynewt-core/fs/disk"
-
 pkg.deps.FS_CLI:
     - "@apache-mynewt-core/sys/shell"
 
diff --git a/fs/fs/src/fs_dirent.c b/fs/fs/src/fs_dirent.c
index c9e46369b..306a82258 100644
--- a/fs/fs/src/fs_dirent.c
+++ b/fs/fs/src/fs_dirent.c
@@ -22,13 +22,13 @@
 
 struct fs_ops *fops_from_filename(const char *);
 
-static struct fs_ops *
+static const struct fs_ops *
 fops_from_dir(const struct fs_dir *dir)
 {
     return fs_ops_from_container((struct fops_container *) dir);
 }
 
-static inline struct fs_ops *
+static inline const struct fs_ops *
 fops_from_dirent(const struct fs_dirent *dirent)
 {
     return fs_ops_from_container((struct fops_container *) dirent);
@@ -37,21 +37,24 @@ fops_from_dirent(const struct fs_dirent *dirent)
 int
 fs_opendir(const char *path, struct fs_dir **out_dir)
 {
-    struct fs_ops *fops = fops_from_filename(path);
-    return fops->f_opendir(path, out_dir);
+    const file_system_t *fs;
+    const char *fs_path;
+    get_file_system_path(path, &fs, &fs_path);
+
+    return fs->ops->f_opendir(fs_path, out_dir);
 }
 
 int
 fs_readdir(struct fs_dir *dir, struct fs_dirent **out_dirent)
 {
-    struct fs_ops *fops = fops_from_dir(dir);
+    const struct fs_ops *fops = fops_from_dir(dir);
     return fops->f_readdir(dir, out_dirent);
 }
 
 int
 fs_closedir(struct fs_dir *dir)
 {
-    struct fs_ops *fops = fops_from_dir(dir);
+    const struct fs_ops *fops = fops_from_dir(dir);
     return fops->f_closedir(dir);
 }
 
@@ -59,13 +62,13 @@ int
 fs_dirent_name(const struct fs_dirent *dirent, size_t max_len,
   char *out_name, uint8_t *out_name_len)
 {
-    struct fs_ops *fops = fops_from_dirent(dirent);
+    const struct fs_ops *fops = fops_from_dirent(dirent);
     return fops->f_dirent_name(dirent, max_len, out_name, out_name_len);
 }
 
 int
 fs_dirent_is_dir(const struct fs_dirent *dirent)
 {
-    struct fs_ops *fops = fops_from_dirent(dirent);
+    const struct fs_ops *fops = fops_from_dirent(dirent);
     return fops->f_dirent_is_dir(dirent);
 }
diff --git a/fs/fs/src/fs_file.c b/fs/fs/src/fs_file.c
index 320a4eacc..33fee7df4 100644
--- a/fs/fs/src/fs_file.c
+++ b/fs/fs/src/fs_file.c
@@ -19,7 +19,6 @@
 #include <fs/fs.h>
 #include <fs/fs_if.h>
 
-#include <disk/disk.h>
 #include <string.h>
 #include <stdlib.h>
 
@@ -123,7 +122,7 @@ fake_dirent_is_dir(const struct fs_dirent *dirent)
     return FS_EUNINIT;
 }
 
-struct fs_ops not_initialized_ops = {
+const struct fs_ops not_initialized_ops = {
     .f_open          = &fake_open,
     .f_close         = &fake_close,
     .f_read          = &fake_read,
@@ -140,13 +139,17 @@ struct fs_ops not_initialized_ops = {
     .f_closedir      = &fake_closedir,
     .f_dirent_name   = &fake_dirent_name,
     .f_dirent_is_dir = &fake_dirent_is_dir,
-    .f_name          = "fakefs",
 };
 
-struct fs_ops *
+const file_system_t fake_fs = {
+    .ops = &not_initialized_ops,
+    .name = "fakefs",
+};
+
+const struct fs_ops *
 safe_fs_ops_for(const char *fs_name)
 {
-    struct fs_ops *fops;
+    const struct fs_ops *fops;
 
     fops = fs_ops_for(fs_name);
     if (fops == NULL) {
@@ -156,31 +159,20 @@ safe_fs_ops_for(const char *fs_name)
     return fops;
 }
 
-struct fs_ops *
-fops_from_filename(const char *filename)
-{
-    char *disk;
-    char *fs_name = NULL;
-    struct fs_ops *unique;
-
-    disk = disk_name_from_path(filename);
-    if (disk) {
-        fs_name = disk_fs_for(disk);
-        free(disk);
-    } else {
-        /**
-         * special case: if only one fs was ever registered,
-         * return that fs' ops.
-         */
-        if ((unique = fs_ops_try_unique()) != NULL) {
-            return unique;
+void
+get_file_system_path(const char *path, const file_system_t **fs, const char **fs_path)
+{
+    *fs_path = file_system_path(path, fs);
+    if (*fs_path == NULL) {
+        *fs = get_only_file_system();
+        if (*fs == NULL) {
+            *fs = &fake_fs;
         }
+        *fs_path = path;
     }
-
-    return safe_fs_ops_for(fs_name);
 }
 
-static inline struct fs_ops *
+static inline const struct fs_ops *
 fops_from_file(const struct fs_file *file)
 {
     return fs_ops_from_container((struct fops_container *) file);
@@ -189,62 +181,68 @@ fops_from_file(const struct fs_file *file)
 int
 fs_open(const char *filename, uint8_t access_flags, struct fs_file **out_file)
 {
-    struct fs_ops *fops = fops_from_filename(filename);
-    return fops->f_open(filename, access_flags, out_file);
+    const file_system_t *fs;
+    const char *fs_filename;
+
+    get_file_system_path(filename, &fs, &fs_filename);
+    return fs->ops->f_open(fs_filename, access_flags, out_file);
 }
 
 int
 fs_close(struct fs_file *file)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_close(file);
 }
 
 int
 fs_read(struct fs_file *file, uint32_t len, void *out_data, uint32_t *out_len)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_read(file, len, out_data, out_len);
 }
 
 int
 fs_write(struct fs_file *file, const void *data, int len)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_write(file, data, len);
 }
 
 int
 fs_seek(struct fs_file *file, uint32_t offset)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_seek(file, offset);
 }
 
 uint32_t
 fs_getpos(const struct fs_file *file)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_getpos(file);
 }
 
 int
 fs_filelen(const struct fs_file *file, uint32_t *out_len)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_filelen(file, out_len);
 }
 
 int
 fs_unlink(const char *filename)
 {
-    struct fs_ops *fops = fops_from_filename(filename);
-    return fops->f_unlink(filename);
+    const file_system_t *fs;
+    const char *fs_filename;
+
+    get_file_system_path(filename, &fs, &fs_filename);
+    return fs->ops->f_unlink(fs_filename);
 }
 
 int
 fs_flush(struct fs_file *file)
 {
-    struct fs_ops *fops = fops_from_file(file);
+    const struct fs_ops *fops = fops_from_file(file);
     return fops->f_flush(file);
 }
diff --git a/fs/fs/src/fs_mkdir.c b/fs/fs/src/fs_mkdir.c
index aca27f59f..223b5527b 100644
--- a/fs/fs/src/fs_mkdir.c
+++ b/fs/fs/src/fs_mkdir.c
@@ -21,18 +21,31 @@
 
 #include "fs_priv.h"
 
-struct fs_ops *fops_from_filename(const char *);
-
 int
 fs_rename(const char *from, const char *to)
 {
-    struct fs_ops *fops = fops_from_filename(from);
-    return fops->f_rename(from, to);
+    const file_system_t *fs1;
+    const file_system_t *fs2;
+    const char *fs_from;
+    const char *fs_to;
+
+    get_file_system_path(from, &fs1, &fs_from);
+    get_file_system_path(to, &fs2, &fs_to);
+
+    if (fs1 == fs2) {
+        return fs1->ops->f_rename(fs_from, fs_to);
+    }
+
+    return FS_EINVAL;
 }
 
 int
 fs_mkdir(const char *path)
 {
-    struct fs_ops *fops = fops_from_filename(path);
-    return fops->f_mkdir(path);
+    const file_system_t *fs;
+    const char *fs_path;
+
+    get_file_system_path(path, &fs, &fs_path);
+
+    return fs->ops->f_mkdir(fs_path);
 }
diff --git a/fs/fs/src/fs_mount.c b/fs/fs/src/fs_mount.c
index c687cf47c..567c1f469 100644
--- a/fs/fs/src/fs_mount.c
+++ b/fs/fs/src/fs_mount.c
@@ -26,68 +26,134 @@
 #include <fs_mgmt/fs_mgmt.h>
 #endif
 
-static SLIST_HEAD(, fs_ops) root_fops = SLIST_HEAD_INITIALIZER();
+#define MAX_MOUNT_POINTS MYNEWT_VAL_FS_MAX_MOUNT_POINTS
 
-#if MYNEWT_VAL(FS_MGMT)
-static uint8_t g_mgmt_initialized;
-#endif
+struct mount_point mount_points[MAX_MOUNT_POINTS];
 
 int
-fs_register(struct fs_ops *fops)
+fs_mount(const file_system_t *fs, const char *mount_point)
 {
-    struct fs_ops *sc;
+    int free_slot = -1;
+    int rc = FS_EOK;
 
-    SLIST_FOREACH(sc, &root_fops, sc_next) {
-        if (strcmp(sc->f_name, fops->f_name) == 0) {
-            return FS_EEXIST;
+    for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) {
+        if (mount_points[i].mount_point == NULL) {
+            if (free_slot < 0) {
+                free_slot = i;
+            }
+        } else if (strcmp(mount_point, mount_points[i].mount_point) == 0) {
+            rc = FS_EEXIST;
+            goto end;
+        }
+    }
+    if (free_slot >= 0) {
+        mount_points[free_slot].mount_point = mount_point;
+        mount_points[free_slot].fs = fs;
+        rc = fs->ops->f_mount ? fs->ops->f_mount(fs) : 0;
+        if (rc) {
+            mount_points[free_slot].mount_point = NULL;
+            mount_points[free_slot].fs = NULL;
         }
+    } else {
+        rc = FS_ENOMEM;
     }
+end:
+    return rc;
+}
 
-    SLIST_INSERT_HEAD(&root_fops, fops, sc_next);
+const file_system_t *
+fs_unmount_mount_point(const char *mount_point)
+{
+    const file_system_t *fs = NULL;
+
+    for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) {
+        if (strcmp(mount_point, mount_points[i].mount_point) == 0) {
+            fs = mount_points[i].fs;
+            mount_points[i].mount_point = NULL;
+            mount_points[i].fs = NULL;
+            break;
+        }
+    }
 
-#if MYNEWT_VAL(FS_MGMT)
-    if (!g_mgmt_initialized) {
-        fs_mgmt_register_group();
-        g_mgmt_initialized = 1;
+    return fs;
+}
+
+int
+fs_unmount_file_system(const file_system_t *fs)
+{
+    int rc = FS_EINVAL;
+
+    for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) {
+        if (mount_points[i].fs == fs) {
+            mount_points[i].mount_point = NULL;
+            mount_points[i].fs = NULL;
+            rc = 0;
+            break;
+        }
     }
+
+    return rc;
+}
+
+#if MYNEWT_VAL(FS_MGMT)
+static uint8_t g_mgmt_initialized;
 #endif
 
-    return FS_EOK;
+int
+fs_register(struct fs_ops *fops)
+{
+    return FS_EINVAL;
 }
 
-struct fs_ops *
-fs_ops_try_unique(void)
+const file_system_t *
+get_only_file_system(void)
 {
-    struct fs_ops *fops = SLIST_FIRST(&root_fops);
+    const file_system_t *fs = NULL;
 
-    if (fops && !SLIST_NEXT(fops, sc_next)) {
-        return fops;
+    for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) {
+        if (mount_points[i].mount_point == NULL) {
+            continue;
+        }
+        if (fs != NULL) {
+            fs = NULL;
+            break;
+        }
+        fs = mount_points[i].fs;
     }
 
-    return NULL;
+    return fs;
 }
 
-struct fs_ops *
-fs_ops_for(const char *fs_name)
+const char *
+file_system_path(const char *uri, const file_system_t **fs)
 {
-    struct fs_ops *fops = NULL;
-    struct fs_ops *sc;
-
-    if (fs_name) {
-        SLIST_FOREACH(sc, &root_fops, sc_next) {
-            if (strcmp(sc->f_name, fs_name) == 0) {
-                fops = sc;
+    const char *fs_path = NULL;
+    const char *m;
+
+    for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) {
+        if (mount_points[i].mount_point != NULL) {
+            fs_path = uri;
+            m = mount_points[i].mount_point;
+            while (*fs_path == *m) {
+                ++fs_path;
+                ++m;
+            }
+            /* Reached end of mount point path ? */
+            if (*m == '\0') {
+                if (fs) {
+                    *fs = mount_points[i].fs;
+                }
                 break;
             }
+            fs_path = NULL;
         }
     }
-
-    return fops;
+    return fs_path;
 }
 
-extern struct fs_ops not_initialized_ops;
+extern const struct fs_ops not_initialized_ops;
 
-struct fs_ops *
+const struct fs_ops *
 fs_ops_from_container(struct fops_container *container)
 {
     if (!container) {
diff --git a/fs/fs/src/fs_priv.h b/fs/fs/src/fs_priv.h
index d5138c938..a336e2893 100644
--- a/fs/fs/src/fs_priv.h
+++ b/fs/fs/src/fs_priv.h
@@ -26,9 +26,8 @@ extern "C" {
 #endif
 
 struct fs_ops;
-struct fs_ops *fs_ops_for(const char *fs_name);
-struct fs_ops *safe_fs_ops_for(const char *fs_name);
-
+const struct fs_ops *fs_ops_for(const char *fs_name);
+const struct fs_ops *safe_fs_ops_for(const char *fs_name);
 
 #ifdef __cplusplus
 }
diff --git a/fs/fs/syscfg.yml b/fs/fs/syscfg.yml
index cc676340c..4cf97388f 100644
--- a/fs/fs/syscfg.yml
+++ b/fs/fs/syscfg.yml
@@ -27,6 +27,13 @@ syscfg.defs:
         description: 'Enables file system mgmt commands.'
         value: 0
 
+    FS_MAX_MOUNT_POINTS:
+        description: >
+            Number of mount point tha can be used.
+            There should be one mount point for each file system that
+            could be mounted.
+        value: 2
+
     FS_UPLOAD_MAX_CHUNK_SIZE:
         description: >
             The maximum amount of file data that can fit in a


(mynewt-core) 08/08: drivers/mmc: Rework to use change disk api

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 48df2deeb176d79619a71ee9d9fe346b995769ed
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Thu Jun 25 15:07:56 2026 +0200

    drivers/mmc: Rework to use change disk api
    
    Code limited card sie to 2GB due to how disk
    API worked (byte addressing).
    Now disk API uses block addressing.
    
    Code was also assuming that only FATFS can be
    used with MMC now card can be used as block
    device that can be mounted locally as FATFS
    but can also be accessed as disk by USB.
    
    Modlog is now supported.
    
    Signed-off-by: Jerzy Kasenberg <je...@codecoup.pl>
---
 hw/drivers/mmc/include/mmc/mmc.h |  76 ++--
 hw/drivers/mmc/pkg.yml           |   2 +
 hw/drivers/mmc/src/mmc.c         | 912 ++++++++++++++++++++++-----------------
 hw/drivers/mmc/syscfg.yml        |  36 +-
 4 files changed, 589 insertions(+), 437 deletions(-)

diff --git a/hw/drivers/mmc/include/mmc/mmc.h b/hw/drivers/mmc/include/mmc/mmc.h
index 07f78b594..4d376cbc3 100644
--- a/hw/drivers/mmc/include/mmc/mmc.h
+++ b/hw/drivers/mmc/include/mmc/mmc.h
@@ -47,67 +47,41 @@ extern "C" {
 #define MMC_ERASE_ERROR       (-11)
 #define MMC_ADDR_ERROR        (-12)
 
-extern struct disk_ops mmc_ops;
-
 struct mmc_spi_cfg {
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+    const char *bus_name;
+#endif
     uint32_t initial_freq_khz;
     uint32_t freq_khz;
+    int pin_cs;
     uint8_t clock_mode;
 };
 
-/**
- * Initialize the MMC driver
- *
- * @param spi_num Number of the SPI channel to be used by MMC
- * @param spi_cfg Low-level device specific SPI configuration
- * @param ss_pin GPIO number of the SS pin
- *
- * @return 0 on success, non-zero on failure
- */
-int
-mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin);
-
-/**
- * Read data from MMC
- *
- * @param mmc_id Id of the MMC device (currently must be 0)
- * @param addr Disk address (in bytes) to be read from
- * @param buf Buffer where data should be copied to
- * @param len Amount of data to read/copy
- *
- * @return 0 on success, non-zero on failure
- */
-int
-mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len);
-
-/**
- * Write data to the MMC
- *
- * @param mmc_id Id of the MMC device (currently must be 0)
- * @param addr Disk address (in bytes) to be written to
- * @param buf Buffer where data should be copied from
- * @param len Amount of data to copy/write
- *
- * @return 0 on success, non-zero on failure
- */
-int
-mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len);
-
-/**
- * TODO
- */
-int
-mmc_ioctl(uint8_t mmc_id, uint32_t cmd, void *arg);
-
+struct mmc_spi {
 #if MYNEWT_VAL(BUS_DRIVER_PRESENT)
-struct mmc_config {
-    struct bus_spi_node_cfg spi_cfg;
-};
-struct mmc {
     struct bus_spi_node node;
+#else
+    int spi_num;
+#endif
+    struct mmc_spi_cfg mmc_spi_cfg;
 };
 
-int mmc_create_dev(struct mmc *mmc, const char *name, struct mmc_config *mmc_cfg);
+typedef struct mmc_disk {
+    struct mmc_spi spi;
+    disk_t disk;
+    disk_info_t disk_info;
+    uint8_t ocr[4];
+    uint8_t csd[16];
+    uint8_t scr[8];
+    uint8_t cid[16];
+    uint8_t app_cmd : 1;
+    struct os_sem sem;
+} mmc_disk_t;
+
+#if MYNEWT_VAL_BUS_DRIVER_PRESENT
+int mmc_create_dev(mmc_disk_t *mmc, const char *name, struct mmc_spi_cfg *mmc_cfg);
+#else
+int mmc_create(mmc_disk_t *mmc, int spi_num, struct mmc_spi_cfg *mmc_cfg);
 #endif
 
 #ifdef __cplusplus
diff --git a/hw/drivers/mmc/pkg.yml b/hw/drivers/mmc/pkg.yml
index d7f9ced40..680bff770 100644
--- a/hw/drivers/mmc/pkg.yml
+++ b/hw/drivers/mmc/pkg.yml
@@ -25,6 +25,8 @@ pkg.keywords:
 
 pkg.deps:
     - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/util/bit_set"
+    - "@apache-mynewt-core/fs/disk"
 
 pkg.deps.BUS_DRIVER_PRESENT:
     - "@apache-mynewt-core/hw/bus/drivers/spi_common"
diff --git a/hw/drivers/mmc/src/mmc.c b/hw/drivers/mmc/src/mmc.c
index 8b93623ef..098d93c8c 100644
--- a/hw/drivers/mmc/src/mmc.c
+++ b/hw/drivers/mmc/src/mmc.c
@@ -24,13 +24,30 @@
 #include <disk/disk.h>
 #include <mmc/mmc.h>
 #include <stdio.h>
+#include <bit_set/bit_set.h>
 
 #define MIN(n, m) (((n) < (m)) ? (n) : (m))
 
+typedef enum {
+    FORMAT_R1,
+    FORMAT_R1B,
+    FORMAT_R2,
+    FORMAT_R3,
+    FORMAT_R4,
+    FORMAT_R5,
+    FORMAT_R6,
+    FORMAT_R7,
+} reponse_format_t;
+
+typedef uint8_t sd_cmd_t;
+
 /* MMC commands used by the driver */
 #define CMD0                (0)            /* GO_IDLE_STATE */
 #define CMD1                (1)            /* SEND_OP_COND (MMC) */
+#define CMD6                (8)            /* SEND_IF_COND */
 #define CMD8                (8)            /* SEND_IF_COND */
+#define CMD9                (9)            /* SEND_CSD */
+#define CMD10               (10)           /* SEND_CID */
 #define CMD12               (12)           /* STOP_TRANSMISSION */
 #define CMD16               (16)           /* SET_BLOCKLEN */
 #define CMD17               (17)           /* READ_SINGLE_BLOCK */
@@ -39,7 +56,10 @@
 #define CMD25               (25)           /* WRITE_MULTIPLE_BLOCK */
 #define CMD55               (55)           /* APP_CMD */
 #define CMD58               (58)           /* READ_OCR */
-#define ACMD41              (0x80 + 41)    /* SEND_OP_COND (SDC) */
+
+#define ACMD13              (13)           /*  */
+#define ACMD41              (41)           /* SEND_OP_COND (SDC) */
+#define ACMD51              (51)           /* SEND_SCR */
 
 #define HCS                 ((uint32_t) 1 << 30)
 
@@ -59,30 +79,57 @@
 #define R_ADDR_ERROR        (0x20)
 #define R_PARAM_ERROR       (0x40)
 
+#define CMD_OK(status)      (((status) & 0x7E) == 0)
+#define CMD_FAILED(status)  (((status) & 0x7E) != 0)
+
 #define START_BLOCK         (0xFE)
 #define START_BLOCK_TOKEN   (0xFC)
 #define STOP_TRAN_TOKEN     (0xFD)
 
 #define BLOCK_LEN           (512)
 
-static uint8_t g_block_buf[BLOCK_LEN + 2];
-
-#if !MYNEWT_VAL(BUS_DRIVER_PRESENT)
-
-static struct mmc {
-    int spi_num;
-    int ss_pin;
-    struct mmc_spi_cfg mmc_spi_cfg;
-} g_mmc;
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
 
-/* FIXME: currently limited to single MMC spi device */
-static struct mmc *mmcs[1] = { &g_mmc };
+static struct mmc_spi_cfg mmc0_config = {
+    .initial_freq_khz = 500,
+    .freq_khz = MYNEWT_VAL_MMC_SPI_FREQ,
+    .clock_mode = MYNEWT_VAL_MMC_SPI_CLOCK_MODE,
+    .bus_name = MYNEWT_VAL_MMC_SPI_BUS_NAME,
+    .pin_cs = MYNEWT_VAL_MMC_SPI_CS_PIN,
+};
 
-#else
-static struct mmc *mmcs[1];
-static uint8_t mmcs_count;
 #endif
 
+const char *
+mmc_error_str(char *buf, uint8_t status)
+{
+    sprintf(buf, "0x%X", status);
+    if (status == 0xff) {
+        strcat(buf, " MMC_CARD_ERROR");
+    } else if (status == 0x7F) {
+        strcat(buf, " Unsupported");
+    } else {
+        if (status & R_IDLE) {
+            strcat(buf, " R_IDLE");
+        }
+        if (status & R_ERASE_RESET) {
+            strcat(buf, " R_ERASE_RESET");
+        }
+        if (status & R_ILLEGAL_COMMAND) {
+            strcat(buf, " R_ILLEGAL_COMMAND");
+        } else if (status & R_CRC_ERROR) {
+            strcat(buf, " R_CRC_ERROR");
+        } else if (status & R_ERASE_ERROR) {
+            strcat(buf, " R_ERASE_ERROR");
+        } else if (status & R_ADDR_ERROR) {
+            strcat(buf, " R_ADDR_ERROR");
+        } else if (status & R_PARAM_ERROR) {
+            strcat(buf, " R_PARAM_ERROR");
+        }
+    }
+    return buf;
+}
+
 static int
 error_by_response(uint8_t status)
 {
@@ -111,90 +158,104 @@ error_by_response(uint8_t status)
     return (rc);
 }
 
-static struct mmc *
-mmc_cfg_dev(uint8_t id)
+static inline void
+mmc_led_on(void)
 {
-    if (id != 0) {
-        return NULL;
+    if (MYNEWT_VAL_MMC_LED_PIN >= 0) {
+        hal_gpio_write(MYNEWT_VAL_MMC_LED_PIN, MYNEWT_VAL_MMC_LED_ON_VALUE);
     }
-
-    return mmcs[0];
 }
 
-#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+static inline void
+mmc_led_off(void)
+{
+    if (MYNEWT_VAL_MMC_LED_PIN >= 0) {
+        hal_gpio_write(MYNEWT_VAL_MMC_LED_PIN, !MYNEWT_VAL_MMC_LED_ON_VALUE);
+    }
+}
 
 static void
-mmc_spi_set_cs(struct mmc *mmc, int cs)
+mmc_spi_set_cs(mmc_disk_t *mmc, int cs)
 {
-    /* Let bus driver actiave CS, deactivation is done here */
-    if (cs) {
-        hal_gpio_write(mmc->node.pin_cs, cs);
-    }
+    hal_gpio_write(mmc->spi.mmc_spi_cfg.pin_cs, cs);
 }
 
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+
 static int
-mmc_spi_tx(struct mmc *mmc, const uint8_t *buf, uint16_t count)
+mmc_spi_tx(mmc_disk_t *mmc, const uint8_t *buf, uint16_t count)
 {
-    return bus_node_write(&mmc->node.bnode.odev, buf, count, 1000, BUS_F_NOSTOP);
+    return bus_node_write(&mmc->spi.node.bnode.odev, buf, count, 1000, BUS_F_NOSTOP);
 }
 
 static int
-mmc_spi_rx(struct mmc *mmc, uint8_t *buf, uint16_t count)
+mmc_spi_rx(mmc_disk_t *mmc, uint8_t *buf, uint16_t count)
 {
     memset(buf, 0xFF, count);
-    return bus_node_duplex_write_read(&mmc->node.bnode.odev, buf, buf, count, 1000, BUS_F_NOSTOP);
+    return bus_node_duplex_write_read(&mmc->spi.node.bnode.odev, buf, buf,
+                                      count, 1000, BUS_F_NOSTOP);
 }
 
 #else
 
-static void
-mmc_spi_set_cs(struct mmc *mmc, int cs)
-{
-    hal_gpio_write(mmc->ss_pin, cs);
-}
-
 static int
-mmc_spi_tx(struct mmc *mmc, const uint8_t *buf, uint16_t count)
+mmc_spi_tx(mmc_disk_t *mmc, const uint8_t *buf, uint16_t count)
 {
+    mmc_led_on();
+
     for (int i = 0; i < count; i++) {
-        hal_spi_tx_val(mmc->spi_num, buf[i]);
+        hal_spi_tx_val(mmc->spi.spi_num, buf[i]);
     }
+
+    mmc_led_off();
     return 0;
 }
 
 static int
-mmc_spi_rx(struct mmc *mmc, uint8_t *buf, uint16_t count)
+mmc_spi_rx(mmc_disk_t *mmc, uint8_t *buf, uint16_t count)
 {
+    mmc_led_on();
+
     for (int i = 0; i < count; i++) {
-        buf[i] = hal_spi_tx_val(mmc->spi_num, 0xFF);
+        buf[i] = hal_spi_tx_val(mmc->spi.spi_num, 0xFF);
     }
+
+    mmc_led_off();
+
     return 0;
 }
 
 #endif
 
 static int
-mmc_spi_tx_byte(struct mmc *mmc, uint8_t b)
+mmc_spi_tx_byte(mmc_disk_t *mmc, uint8_t b)
 {
     return mmc_spi_tx(mmc, &b, 1);
 }
 
+static inline void
+mmc_send_extra_clocks(mmc_disk_t *mmc)
+{
+    static const uint8_t extra_bytes[] = { 0xFF, 0xFF, 0xFF };
+
+    if (MYNEWT_VAL_MMC_SEND_EXTRA_CLOCKS) {
+        mmc_spi_tx(mmc, extra_bytes, sizeof(extra_bytes));
+    }
+}
+
 static uint8_t
-send_mmc_cmd(struct mmc *mmc, uint8_t cmd, uint32_t payload)
+send_mmc_cmd(mmc_disk_t *mmc, sd_cmd_t cmd, uint32_t payload)
 {
     int n;
-    uint8_t status;
+    uint16_t status;
     uint8_t crc;
     uint8_t buf[6];
+    char strbuf[30];
 
-    if (cmd & 0x80) {
-        /* TODO: refactor recursion? */
-        /* TODO: error checking */
-        send_mmc_cmd(mmc, CMD55, 0);
-    }
+    mmc_led_on();
 
     /* 4.7.2: Command Format */
-    buf[0] = 0x40 | (cmd & ~0x80);
+    buf[0] = 0x40 | cmd;
     buf[1] = (uint8_t)(payload >> 24);
     buf[2] = (uint8_t)(payload >> 16);
     buf[3] = (uint8_t)(payload >> 8);
@@ -220,213 +281,309 @@ send_mmc_cmd(struct mmc *mmc, uint8_t cmd, uint32_t payload)
     buf[5] = crc;
     mmc_spi_tx(mmc, buf, 6);
 
-    for (n = 255; n > 0; n--) {
+    for (n = 10; n > 0; n--) {
         mmc_spi_rx(mmc, buf, 1);
         status = buf[0];
-        if ((status & 0x80) == 0) {
-            break;
+        if (status != 0xFF) {
+            if (status & 0x80) {
+                mmc_spi_rx(mmc, buf, 1);
+                status = status << 8 | buf[0];
+                while (status & 0x8000) {
+                    status <<= 1;
+                }
+                status >>= 8;
+            }
+            if (status != 0x7F) {
+                break;
+            }
         }
     }
+    if (CMD_FAILED(status)) {
+        MMC_LOG_ERROR("%sCMD%d status %s", mmc->app_cmd ? "A" : "", cmd,
+                      mmc_error_str(strbuf, status));
+    } else {
+        MMC_LOG_DEBUG("%sCMD%d status %s", mmc->app_cmd ? "A" : "", cmd,
+                      mmc_error_str(strbuf, status));
+    }
+    mmc->app_cmd = 0;
 
-    return status;
-}
+    mmc_led_off();
 
-#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+    return (uint8_t)status;
+}
 
-static void
-mmc_open_cb(struct bus_node *node)
+static uint8_t
+mmc_cmd_rx(mmc_disk_t *mmc, uint8_t cmd, uint32_t payload, uint8_t response[],
+           size_t response_size)
 {
-    int rc;
-    int i;
     uint8_t status;
-    uint8_t cmd_resp[4];
-    uint32_t ocr;
-    os_time_t timeout;
-    struct mmc *mmc = (struct mmc *)node;
 
-    /**
-     * NOTE: The state machine below follows:
-     *       Section 6.4.1: Power Up Sequence for SD Bus Interface.
-     *       Section 7.2.1: Mode Selection and Initialization.
-     */
-
-    /* give 10ms for VDD rampup */
-    os_time_delay(OS_TICKS_PER_SEC / 100);
+    mmc_spi_set_cs(mmc, 0);
+    status = send_mmc_cmd(mmc, cmd, payload);
 
-    /* send the required >= 74 clock cycles (10 bytes, 80 clock cycles). */
-    for (i = 0; i < 10; i++) {
-        mmc_spi_tx_byte(mmc, 0xff);
+    if (response_size && response != NULL && CMD_OK(status)) {
+        mmc_spi_rx(mmc, response, response_size);
     }
 
-    /* put card in idle state */
-    status = send_mmc_cmd(mmc, CMD0, 0);
-
     mmc_spi_set_cs(mmc, 1);
-    /* No card inserted or bad card? */
-    if (status != R_IDLE) {
-        rc = error_by_response(status);
-        goto out;
-    }
 
-    /**
-     * FIXME: while doing a hot-swap of the card or powering off the board
-     * it is required to send a CMD1 here otherwise CMD8's response will
-     * be always invalid.
-     *
-     * Why is this happening? CMD1 should never be required for SDxC cards...
-     */
+    mmc_send_extra_clocks(mmc);
 
-    /**
-     * 4.3.13: Ask for 2.7-3.3V range, send 0xAA pattern
-     *
-     * NOTE: cards that are not compliant with "Physical Spec Version 2.00"
-     *       will answer this with R_ILLEGAL_COMMAND.
-     */
-    status = send_mmc_cmd(mmc, CMD8, 0x1AA);
-    if (status != 0xff && !(status & R_ILLEGAL_COMMAND)) {
+    return status;
+}
 
-        /**
-         * Ver2.00 or later SD Memory Card
-         */
+static uint8_t
+mmc_cmd_r1(mmc_disk_t *mmc, uint8_t cmd, uint32_t payload)
+{
+    return mmc_cmd_rx(mmc, cmd, payload, NULL, 0);
+}
 
-        /* Read the contents of R7 */
-        mmc_spi_rx(mmc, cmd_resp, 4);
+static uint8_t
+mmc_wait_for_data(mmc_disk_t *mmc, uint32_t timeout_ms)
+{
+    os_time_t timeout = os_time_get() + os_time_ms_to_ticks32(timeout_ms);
+    uint8_t res;
 
-        /* Did the card return the same pattern? */
-        if (cmd_resp[3] != 0xAA) {
-            rc = MMC_RESPONSE_ERROR;
-            goto out;
+    do {
+        mmc_spi_rx(mmc, &res, 1);
+        if (res != 0xFF) {
+            break;
         }
+    } while (OS_TIME_TICK_LT(os_time_get(), timeout));
 
-        /**
-         * 4.3.13 Send Interface Condition Command (CMD8)
-         *   Check VHS for 2.7-3.6V support
-         */
-        if (cmd_resp[2] != 0x01) {
-            rc = MMC_VOLTAGE_ERROR;
-            goto out;
-        }
+    return res;
+}
 
-        /**
-         * Wait for card to leave IDLE state or time out
-         */
+static uint8_t
+mmc_cmd_receive_data(mmc_disk_t *mmc, uint8_t cmd, uint32_t payload,
+                     uint8_t *buffer, int count)
+{
+    int status;
+    uint8_t res;
 
-        timeout = os_time_get() + OS_TICKS_PER_SEC;
-        for (;;) {
-            status = send_mmc_cmd(mmc, ACMD41, HCS);
-            if ((status & R_IDLE) == 0 || os_time_get() > timeout) {
-                break;
-            }
-            os_time_delay(OS_TICKS_PER_SEC / 10);
-        }
+    mmc_spi_set_cs(mmc, 0);
 
-        if (status) {
-            rc = error_by_response(status);
-            goto out;
+    status = send_mmc_cmd(mmc, cmd, payload);
+
+    if (CMD_OK(status)) {
+        res = mmc_wait_for_data(mmc, 20);
+        if (res == START_BLOCK) {
+            mmc_spi_rx(mmc, buffer, count);
         }
+    }
 
-        /**
-         * Check if this is an high density card
-         */
+    mmc_spi_set_cs(mmc, 1);
 
-        status = send_mmc_cmd(mmc, CMD58, 0);
-        mmc_spi_rx(mmc, cmd_resp, 4);
-        if (status == 0 && (cmd_resp[0] & (1 << 6))) {  /* FIXME: CCS */
-            /**
-             * TODO: if CCS is set this is an SDHC or SDXC card!
-             *       SDSC uses byte addressing, SDHC/SDXC block addressing
-             *
-             *       can also check the whole voltage range supported here
-             */
-        }
+    mmc_send_extra_clocks(mmc);
 
-    } else if (status != 0xff && status & R_ILLEGAL_COMMAND) {
+    return status;
+}
 
-        /**
-         * Ver1.x SD Memory Card or Not SD Memory Card
-         */
+static uint8_t
+mmc_acmd(mmc_disk_t *mmc, uint8_t cmd, uint32_t payload, uint8_t *response,
+         size_t response_size)
+{
+    uint8_t status;
 
-        ocr = send_mmc_cmd(mmc, CMD58, 0);
+    status = mmc_cmd_r1(mmc, CMD55, 0);
+    if (CMD_OK(status)) {
+        mmc->app_cmd = 1;
+        status = mmc_cmd_rx(mmc, cmd, payload, response, response_size);
+    }
 
-        /* TODO: check if voltage range is ok! */
+    return status;
+}
 
-        if (ocr & R_ILLEGAL_COMMAND) {
+static uint8_t
+mmc_acmd_with_data(mmc_disk_t *mmc, uint8_t cmd, uint32_t payload,
+                   uint8_t *buffer, size_t count)
+{
+    uint8_t status;
 
-        }
+    status = mmc_cmd_r1(mmc, CMD55, 0);
 
-        /* TODO: set blocklen */
+    if (CMD_OK(status)) {
+        mmc->app_cmd = 1;
+        status = mmc_cmd_receive_data(mmc, cmd, payload, buffer, count);
+    }
 
+    return status;
+}
+
+#define SCR_SCR_STRUCTURE_POS       60
+#define SCR_SCR_STRUCTURE_LEN       4
+#define SCR_SD_SPEC_POS             56
+#define SCR_SD_SPEC_LEN             4
+#define SD_BUS_WIDTHS_POS           48
+#define SD_BUS_WIDTHS_LEN           4
+#define SCR_SD_SPEC3_POS            47
+#define SCR_SD_SPEC3_LEN            1
+#define SCR_CMD_SUPPORT_POS         32
+#define SCR_CMD_SUPPORT_LEN         14
+
+#define CSD_V1_CSD_STRUCTURE_POS    126
+#define CSD_V1_CSD_STRUCTURE_LEN    2
+#define CSD_V1_CSD_STRUCTURE_VER_1  0
+#define CSD_V1_READ_BL_LEN_POS      80
+#define CSD_V1_READ_BL_LEN_LEN      4
+#define CSD_V1_C_SIZE_POS           62
+#define CSD_V1_C_SIZE_LEN           12
+#define CSD_V1_C_SIZE_MULT_POS      47
+#define CSD_V1_C_SIZE_MULT_LEN      3
+
+#define CSD_V2_CSD_STRUCTURE_POS    126
+#define CSD_V2_CSD_STRUCTURE_LEN    2
+#define CSD_V2_CSD_STRUCTURE_VER_2  1
+#define CSD_V2_C_SIZE_POS           48
+#define CSD_V2_C_SIZE_LEN           22
+
+static uint32_t
+csd_sector_count(const uint8_t csd[16])
+{
+    uint32_t ver = bit_set_get_uint32(csd, CSD_V1_CSD_STRUCTURE_POS,
+                                      CSD_V1_CSD_STRUCTURE_LEN);
+    uint32_t c_size;
+    uint32_t c_size_mult;
+
+    if (ver == CSD_V1_CSD_STRUCTURE_VER_1) {
+        c_size = bit_set_get_uint32(csd, CSD_V1_C_SIZE_POS, CSD_V1_C_SIZE_LEN);
+        c_size_mult = bit_set_get_uint32(csd, CSD_V1_C_SIZE_MULT_POS,
+                                         CSD_V1_C_SIZE_MULT_LEN);
+        return (c_size + 1) << (c_size_mult + 2);
     } else {
-        rc = error_by_response(status);
+        c_size = bit_set_get_uint32(csd, CSD_V2_C_SIZE_POS, CSD_V2_C_SIZE_LEN);
+        return (c_size + 1) << 10;
     }
-
-out:
-    mmc_spi_set_cs(mmc, 1);
-    (void)rc;
 }
 
 int
-mmc_create_dev(struct mmc *mmc, const char *name, struct mmc_config *mmc_cfg)
+mmc_read_csd(mmc_disk_t *mmc, uint8_t csd[16])
 {
-    int rc;
-    struct bus_node_callbacks cbs = {
-        .open = mmc_open_cb,
-    };
+    uint8_t status;
+    uint32_t ver;
+    uint32_t c_size;
 
-    bus_node_set_callbacks((struct os_dev *)mmc, &cbs);
+    status = mmc_cmd_receive_data(mmc, CMD9, 0, csd, 16);
+
+    if (CMD_OK(status)) {
+        bit_set_reverse(csd, 128);
 
-    rc = bus_spi_node_create(name, &mmc->node, &mmc_cfg->spi_cfg, NULL);
-    if (rc == 0 && mmcs_count < ARRAY_SIZE(mmcs)) {
-        mmcs[mmcs_count++] = mmc;
+        ver = bit_set_get_uint32(csd, CSD_V1_CSD_STRUCTURE_POS,
+                                 CSD_V1_CSD_STRUCTURE_LEN);
+        MMC_LOG_INFO("CSD ver %d", ver == CSD_V1_CSD_STRUCTURE_VER_1 ? 1 : 2);
+
+        if (ver == CSD_V1_CSD_STRUCTURE_VER_1) {
+            c_size = bit_set_get_uint32(csd, CSD_V1_C_SIZE_POS, CSD_V1_C_SIZE_LEN);
+            MMC_LOG_DEBUG("CSD c_size %d c_size_mult %d read_bl_len %d)", (int)c_size,
+                          (int)bit_set_get_uint32(csd, CSD_V1_C_SIZE_MULT_POS,
+                                                  CSD_V1_C_SIZE_MULT_LEN),
+                          (int)bit_set_get_uint32(csd, CSD_V1_READ_BL_LEN_POS,
+                                                  CSD_V1_READ_BL_LEN_LEN));
+        } else {
+            c_size = bit_set_get_uint32(csd, CSD_V2_C_SIZE_POS, CSD_V2_C_SIZE_LEN);
+            MMC_LOG_DEBUG("CSD c_size %d (%ul sectors %u MB)", (int)c_size,
+                          csd_sector_count(csd), csd_sector_count(csd) >> 11);
+        }
     }
 
-    return rc;
+    return status;
 }
 
-#else
-/**
- * Initialize the MMC driver
- *
- * @param spi_num Number of the SPI channel to be used by MMC
- * @param spi_cfg Low-level device specific SPI configuration
- * @param ss_pin Number of SS pin if SW controlled, -1 otherwise
- *
- * @return 0 on success, non-zero on failure
- */
-int
-mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
+uint8_t
+mmc_read_cid(mmc_disk_t *mmc, uint8_t cid[16])
 {
-    int rc;
-    int i;
     uint8_t status;
-    uint8_t cmd_resp[4];
-    uint32_t ocr;
-    os_time_t timeout;
-    /* TODO: create new struct for every new spi mmc, add to SLIST */
-    struct mmc *mmc = mmcs[0];
-    mmc->ss_pin = ss_pin;
-    mmc->mmc_spi_cfg = *spi_cfg;
 
-    mmc->spi_num = spi_num;
+    status = mmc_cmd_receive_data(mmc, CMD10, 0, (uint8_t *)cid, 16);
+
+    if (CMD_OK(status)) {
+        MMC_LOG_INFO("CID MID 0x%x", cid[0]);
+        MMC_LOG_INFO("CID OID %c%c", cid[1], cid[2]);
+        MMC_LOG_INFO("CID PNM %c%c%c%c%c", cid[3], cid[4], cid[5], cid[6], cid[7]);
+        MMC_LOG_INFO("CID PRV %c.%c", (cid[8] >> 4) + '0', (cid[8] & 15) + '0');
+        MMC_LOG_INFO("CID MDT %d.%02d",
+                     2000 + ((cid[13] & 15) << 4) + (cid[14] >> 4), (cid[14] & 15));
+    }
+
+    return status;
+}
+
+uint8_t
+mmc_read_scr(mmc_disk_t *mmc, uint8_t scr[8])
+{
+    uint8_t status;
+
+    status = mmc_acmd_with_data(mmc, ACMD51, 0, scr, 8);
+
+    if (CMD_OK(status)) {
+        bit_set_reverse(scr, 64);
+        MMC_LOG_INFO("SCR structure %d",
+                     (int)bit_set_get_uint32(scr, SCR_SCR_STRUCTURE_POS,
+                                             SCR_SCR_STRUCTURE_LEN));
+        MMC_LOG_INFO("SCR sd_spec %d",
+                     (int)bit_set_get_uint32(scr, SCR_SD_SPEC_POS, SCR_SD_SPEC_LEN));
+        MMC_LOG_INFO("SCR sd_bus_width 0x%x",
+                     (int)bit_set_get_uint32(scr, SD_BUS_WIDTHS_POS, SD_BUS_WIDTHS_LEN));
+    }
+
+    return status;
+}
+
+static void
+mmc_set_init_settings(mmc_disk_t *mmc)
+{
+#if MYNEWT_VAL_BUS_DRIVER_PRESENT
+    mmc->spi.node.freq = mmc->spi.mmc_spi_cfg.initial_freq_khz;
+#else
+    int rc;
+
     struct hal_spi_settings spi_settings = {
         .data_order = HAL_SPI_MSB_FIRST,
-        .data_mode = mmc->mmc_spi_cfg.clock_mode,
-        .baudrate = mmc->mmc_spi_cfg.initial_freq_khz,
+        .data_mode = mmc->spi.mmc_spi_cfg.clock_mode,
+        .baudrate = mmc->spi.mmc_spi_cfg.initial_freq_khz,
         .word_size = HAL_SPI_WORD_SIZE_8BIT,
     };
 
-    hal_gpio_init_out(mmc->ss_pin, 1);
-
-    rc = hal_spi_config(mmc->spi_num, &spi_settings);
-    if (rc) {
-        return (rc);
+    hal_spi_disable(mmc->spi.spi_num);
+    rc = hal_spi_config(mmc->spi.spi_num, &spi_settings);
+    if (rc == 0) {
+        hal_spi_enable(mmc->spi.spi_num);
     }
+#endif
+}
 
-    hal_spi_set_txrx_cb(mmc->spi_num, NULL, NULL);
-    rc = hal_spi_enable(mmc->spi_num);
-    if (rc) {
-        return (rc);
+static void
+mmc_set_working_settings(mmc_disk_t *mmc)
+{
+#if MYNEWT_VAL_BUS_DRIVER_PRESENT
+    mmc->spi.node.freq = mmc->spi.mmc_spi_cfg.freq_khz;
+#else
+    int rc;
+
+    struct hal_spi_settings spi_settings = {
+        .data_order = HAL_SPI_MSB_FIRST,
+        .data_mode = mmc->spi.mmc_spi_cfg.clock_mode,
+        .baudrate = mmc->spi.mmc_spi_cfg.freq_khz,
+        .word_size = HAL_SPI_WORD_SIZE_8BIT,
+    };
+
+    hal_spi_disable(mmc->spi.spi_num);
+    rc = hal_spi_config(mmc->spi.spi_num, &spi_settings);
+    if (rc == 0) {
+        hal_spi_enable(mmc->spi.spi_num);
     }
+#endif
+    MMC_LOG_INFO("Switching to %d kHz", mmc->spi.mmc_spi_cfg.freq_khz);
+}
+
+static int
+mmc_init(mmc_disk_t *mmc)
+{
+    int rc = 0;
+    uint8_t status;
+    uint8_t cmd_resp[4];
+    uint8_t buf[10] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+    os_time_t timeout;
 
     /**
      * NOTE: The state machine below follows:
@@ -437,28 +594,25 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
     /* give 10ms for VDD rampup */
     os_time_delay(OS_TICKS_PER_SEC / 100);
 
-    mmc_spi_set_cs(mmc, 0);
+    mmc_set_init_settings(mmc);
 
+    mmc_spi_set_cs(mmc, 1);
+
+    MMC_LOG_DEBUG("Send clocks to switch to SPI mode");
     /* send the required >= 74 clock cycles (10 bytes, 80 clock cycles). */
-    for (i = 0; i < 10; i++) {
-        mmc_spi_tx_byte(mmc, 0xff);
-    }
+    mmc_spi_tx(mmc, buf, 10);
 
     /* put card in idle state */
-    status = send_mmc_cmd(mmc, CMD0, 0);
+    status = mmc_cmd_r1(mmc, CMD0, 0);
 
-    mmc_spi_set_cs(mmc, 1);
     /* No card inserted or bad card? */
     if (status != R_IDLE) {
-        rc = error_by_response(status);
+        MMC_LOG_ERROR("Card not detected");
+        rc = MMC_CARD_ERROR;
         goto out;
     }
 
-    hal_spi_disable(mmc->spi_num);
-    spi_settings.baudrate = mmc->mmc_spi_cfg.freq_khz;
-    rc = hal_spi_config(mmc->spi_num, &spi_settings);
-    hal_spi_enable(mmc->spi_num);
-    mmc_spi_set_cs(mmc, 0);
+    mmc_set_working_settings(mmc);
 
     /**
      * FIXME: while doing a hot-swap of the card or powering off the board
@@ -474,18 +628,19 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
      * NOTE: cards that are not compliant with "Physical Spec Version 2.00"
      *       will answer this with R_ILLEGAL_COMMAND.
      */
-    status = send_mmc_cmd(mmc, CMD8, 0x1AA);
+    status = mmc_cmd_rx(mmc, CMD8, 0x1AA, cmd_resp, 4);
+    if (status != R_IDLE) {
+        status = mmc_cmd_rx(mmc, CMD8, 0x1AA, cmd_resp, 4);
+    }
     if (status != 0xff && !(status & R_ILLEGAL_COMMAND)) {
 
         /**
          * Ver2.00 or later SD Memory Card
          */
 
-        /* Read the contents of R7 */
-        mmc_spi_rx(mmc, cmd_resp, 4);
-
         /* Did the card return the same pattern? */
         if (cmd_resp[3] != 0xAA) {
+            MMC_LOG_ERROR("CMD8 response error %02x%02x", cmd_resp[2], cmd_resp[3]);
             rc = MMC_RESPONSE_ERROR;
             goto out;
         }
@@ -495,6 +650,7 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
          *   Check VHS for 2.7-3.6V support
          */
         if (cmd_resp[2] != 0x01) {
+            MMC_LOG_ERROR("CMD8 voltage error %02x%02x", cmd_resp[2], cmd_resp[3]);
             rc = MMC_VOLTAGE_ERROR;
             goto out;
         }
@@ -505,7 +661,7 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
 
         timeout = os_time_get() + OS_TICKS_PER_SEC;
         for (;;) {
-            status = send_mmc_cmd(mmc, ACMD41, HCS);
+            status = mmc_acmd(mmc, ACMD41, HCS, NULL, 0);
             if ((status & R_IDLE) == 0 || os_time_get() > timeout) {
                 break;
             }
@@ -513,7 +669,6 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
         }
 
         if (status) {
-            rc = error_by_response(status);
             goto out;
         }
 
@@ -521,42 +676,113 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin)
          * Check if this is an high density card
          */
 
-        status = send_mmc_cmd(mmc, CMD58, 0);
-        mmc_spi_rx(mmc, cmd_resp, 4);
-        if (status == 0 && (cmd_resp[0] & (1 << 6))) {  /* FIXME: CCS */
-            /**
-             * TODO: if CCS is set this is an SDHC or SDXC card!
-             *       SDSC uses byte addressing, SDHC/SDXC block addressing
-             *
-             *       can also check the whole voltage range supported here
-             */
+        status = mmc_cmd_rx(mmc, CMD58, 0, mmc->ocr, 4);
+        if (CMD_FAILED(status)) {
+            goto out;
         }
 
+        memset(&mmc->csd, 0, sizeof(mmc->csd));
+        memset(&mmc->cid, 0, sizeof(mmc->cid));
+        memset(&mmc->scr, 0, sizeof(mmc->scr));
+
+        /* CMD9 read csd */
+        status = mmc_read_csd(mmc, mmc->csd);
+        if (CMD_FAILED(status)) {
+            goto out;
+        }
+        /* ACMD51 read scr */
+        status = mmc_read_scr(mmc, mmc->scr);
+        if (CMD_FAILED(status)) {
+            goto out;
+        }
+        /* CMD10 read cid, some older cards don't have this */
+        (void)mmc_read_cid(mmc, mmc->cid);
     } else if (status != 0xff && status & R_ILLEGAL_COMMAND) {
 
+        mmc_cmd_r1(mmc, CMD0, 0);
         /**
          * Ver1.x SD Memory Card or Not SD Memory Card
          */
 
-        ocr = send_mmc_cmd(mmc, CMD58, 0);
+        status = mmc_cmd_rx(mmc, CMD58, 0, cmd_resp, 4);
+    }
 
-        /* TODO: check if voltage range is ok! */
+out:
+    if (rc == 0 && status != 0) {
+        rc = error_by_response(status);
+    }
+    return rc;
+}
 
-        if (ocr & R_ILLEGAL_COMMAND) {
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
 
-        }
+static void
+mmc_open_cb(struct bus_node *node)
+{
+    mmc_disk_t *mmc = CONTAINER_OF(node, mmc_disk_t, spi);
+    mmc_init(mmc);
+}
 
-        /* TODO: set blocklen */
+int
+mmc_create_dev(mmc_disk_t *mmc, const char *name, struct mmc_spi_cfg *mmc_cfg)
+{
+    int rc;
+    struct bus_node_callbacks cbs = {
+        .open = mmc_open_cb,
+    };
+    struct bus_spi_node_cfg spi_cfg = {
+        .freq = mmc_cfg->initial_freq_khz,
+        .pin_cs = -1,
+        .data_order = BUS_SPI_DATA_ORDER_MSB,
+        .mode = mmc_cfg->clock_mode,
+        .node_cfg.bus_name = mmc_cfg->bus_name,
+    };
 
-    } else {
-        rc = error_by_response(status);
+    if (mmc_cfg->pin_cs >= 0) {
+        hal_gpio_init_out(mmc_cfg->pin_cs, 1);
     }
 
-out:
-    mmc_spi_set_cs(mmc, 1);
+    mmc->spi.mmc_spi_cfg = *mmc_cfg;
+    os_sem_init(&mmc->sem, 0);
+    bus_node_set_callbacks((struct os_dev *)mmc, &cbs);
+
+    rc = bus_spi_node_create(name, &mmc->spi.node, &spi_cfg, NULL);
+
     return rc;
 }
 
+#else
+
+int
+mmc_create(mmc_disk_t *mmc, int spi_num, struct mmc_spi_cfg *mmc_cfg)
+{
+    int rc;
+
+    mmc->spi.spi_num = spi_num;
+    mmc->spi.mmc_spi_cfg = *mmc_cfg;
+
+    struct hal_spi_settings spi_settings = {
+        .data_order = HAL_SPI_MSB_FIRST,
+        .data_mode = mmc->spi.mmc_spi_cfg.clock_mode,
+        .baudrate = mmc->spi.mmc_spi_cfg.initial_freq_khz,
+        .word_size = HAL_SPI_WORD_SIZE_8BIT,
+    };
+
+    hal_gpio_init_out(mmc->spi.mmc_spi_cfg.pin_cs, 1);
+
+    rc = hal_spi_config(mmc->spi.spi_num, &spi_settings);
+    if (rc) {
+        return (rc);
+    }
+
+    hal_spi_set_txrx_cb(mmc->spi.spi_num, NULL, NULL);
+    rc = hal_spi_enable(mmc->spi.spi_num);
+    if (rc) {
+        return (rc);
+    }
+    return 0;
+}
+
 #endif
 
 /**
@@ -565,7 +791,7 @@ out:
  * operations are in progress.
  */
 static uint8_t
-wait_busy(struct mmc *mmc)
+wait_busy(mmc_disk_t *mmc)
 {
     os_time_t timeout;
     uint8_t res;
@@ -582,59 +808,57 @@ wait_busy(struct mmc *mmc)
     return res;
 }
 
+static int
+mmc_get_info(const struct disk *disk, struct disk_info *info)
+{
+    mmc_disk_t *mmc = CONTAINER_OF(disk, mmc_disk_t, disk);
+
+    *info = mmc->disk_info;
+
+    return 0;
+}
+
+static int
+mmc_eject(struct disk *disk)
+{
+    mmc_disk_t *mmc = CONTAINER_OF(disk, mmc_disk_t, disk);
+    /* TODO: Check what needs to be done here */
+
+    mmc->disk_info.present = false;
+    return 0;
+}
+
 /**
  * @return 0 on success, non-zero on failure
  */
-int
-mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len)
+static int
+mmc_read(struct disk *disk, uint32_t lba, void *buf, uint32_t block_count)
 {
     uint8_t cmd;
     uint8_t res;
     int rc;
-    size_t block_len;
-    size_t block_count;
-    os_time_t timeout;
-    uint32_t block_addr;
-    size_t offset;
-    size_t index;
-    size_t amount;
-    struct mmc *mmc;
+    mmc_disk_t *mmc;
+    uint8_t crc[2];
 
-    mmc = mmc_cfg_dev(mmc_id);
-    if (mmc == NULL) {
-        return (MMC_DEVICE_ERROR);
-    }
+    mmc = CONTAINER_OF(disk, mmc_disk_t, disk);
 
     rc = MMC_OK;
 
-    block_len = (len + BLOCK_LEN - 1) & ~(BLOCK_LEN - 1);
-    block_count = block_len / BLOCK_LEN;
-    block_addr = addr / BLOCK_LEN;
-    offset = addr - (block_addr * BLOCK_LEN);
-
     mmc_spi_set_cs(mmc, 0);
 
     cmd = (block_count == 1) ? CMD17 : CMD18;
-    res = send_mmc_cmd(mmc, cmd, block_addr);
+    res = send_mmc_cmd(mmc, cmd, lba);
     if (res) {
         rc = error_by_response(res);
         goto out;
     }
 
-    index = 0;
     while (block_count--) {
         /**
          * 7.3.3 Control tokens
          *   Wait up to 200ms for control token.
          */
-        timeout = os_time_get() + OS_TICKS_PER_SEC / 5;
-        do {
-            mmc_spi_rx(mmc, &res, 1);
-            if (res != 0xFF) {
-                break;
-            }
-            os_time_delay(OS_TICKS_PER_SEC / 20);
-        } while (os_time_get() < timeout);
+        res = mmc_wait_for_data(mmc, 200);
 
         /**
          * 7.3.3.2 Start Block Tokens and Stop Tran Token
@@ -644,23 +868,16 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len)
             goto out;
         }
 
-        mmc_spi_rx(mmc, g_block_buf, BLOCK_LEN + 2 /* CRC */);
-
-        /* TODO: CRC-16 not used here but would be cool to have */
-
-        amount = MIN(BLOCK_LEN - offset, len);
+        mmc_spi_rx(mmc, buf, BLOCK_LEN);
+        mmc_spi_rx(mmc, crc, 2);
 
-        memcpy(((uint8_t *)buf + index), &g_block_buf[offset], amount);
-
-        offset = 0;
-        len -= amount;
-        index += amount;
+        buf = (uint8_t *)buf + BLOCK_LEN;
     }
 
     if (cmd == CMD18) {
         send_mmc_cmd(mmc, CMD12, 0);
-        wait_busy(mmc);
     }
+    wait_busy(mmc);
 
 out:
     mmc_spi_set_cs(mmc, 1);
@@ -671,74 +888,25 @@ out:
  * @return 0 on success, non-zero on failure
  */
 int
-mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len)
+mmc_write(struct disk *disk, uint32_t lba, const void *buf, uint32_t block_count)
 {
     uint8_t cmd;
     uint8_t res;
-    size_t block_len;
-    size_t block_count;
-    os_time_t timeout;
-    uint32_t block_addr;
-    size_t offset;
-    size_t index;
-    size_t amount;
+    uint8_t crc[2] = { 0xFF, 0xFF };
     int rc;
-    struct mmc *mmc;
-
-    mmc = mmc_cfg_dev(mmc_id);
-    if (mmc == NULL) {
-        return (MMC_DEVICE_ERROR);
-    }
-
-    block_len = (len + BLOCK_LEN - 1) & ~(BLOCK_LEN - 1);
-    block_count = block_len / BLOCK_LEN;
-    block_addr = addr / BLOCK_LEN;
-    offset = addr - (block_addr * BLOCK_LEN);
+    mmc_disk_t *mmc;
+    mmc = CONTAINER_OF(disk, mmc_disk_t, disk);
 
     mmc_spi_set_cs(mmc, 0);
 
-    /**
-     * This code ensures that if the requested address doesn't align with the
-     * beginning address of a sector, the initial bytes are first read to the
-     * buffer to be then written later.
-     *
-     * NOTE: this code will never run when using a FS that is sector addressed
-     * like FAT (offset is always 0).
-     */
-    if (offset) {
-        res = send_mmc_cmd(mmc, CMD17, block_addr);
-        if (res != 0) {
-            rc = error_by_response(res);
-            goto out;
-        }
-
-        timeout = os_time_get() + OS_TICKS_PER_SEC / 5;
-        do {
-            mmc_spi_rx(mmc, &res, 1);
-            if (res != 0xff) {
-                break;
-            }
-            os_time_delay(OS_TICKS_PER_SEC / 20);
-        } while (os_time_get() < timeout);
-
-        if (res != START_BLOCK) {
-            rc = MMC_CARD_ERROR;
-            goto out;
-        }
-
-        mmc_spi_rx(mmc, g_block_buf, BLOCK_LEN + 2);
-    }
-
     /* now start write */
-
     cmd = (block_count == 1) ? CMD24 : CMD25;
-    res = send_mmc_cmd(mmc, cmd, block_addr);
+    res = send_mmc_cmd(mmc, cmd, lba);
     if (res) {
         rc = error_by_response(res);
         goto out;
     }
 
-    index = 0;
     while (block_count--) {
         /**
          * 7.3.3.2 Start Block Tokens and Stop Tran Token
@@ -749,13 +917,8 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len)
             mmc_spi_tx_byte(mmc, START_BLOCK_TOKEN);
         }
 
-        amount = MIN(BLOCK_LEN - offset, len);
-        memcpy(&g_block_buf[offset], ((uint8_t *)buf + index), amount);
-
-        /* CRC */
-        g_block_buf[BLOCK_LEN] = 0xFF;
-        g_block_buf[BLOCK_LEN + 1] = 0xFF;
-        mmc_spi_tx(mmc, g_block_buf, BLOCK_LEN + 2);
+        mmc_spi_tx(mmc, buf, BLOCK_LEN);
+        mmc_spi_tx(mmc, crc, 2);
 
         /**
          * 7.3.3.1 Data Response Token
@@ -769,9 +932,7 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len)
             wait_busy(mmc);
         }
 
-        offset = 0;
-        len -= amount;
-        index += amount;
+        buf = (uint8_t *)buf + BLOCK_LEN;
     }
 
     if (cmd == CMD25) {
@@ -802,65 +963,46 @@ out:
 /*
  *
  */
-int
-mmc_ioctl(uint8_t mmc_id, uint32_t cmd, void *arg)
-{
-    return 0;
-}
-
-/*
- *
- */
-struct disk_ops mmc_ops = {
-    .read  = &mmc_read,
-    .write = &mmc_write,
-    .ioctl = &mmc_ioctl,
+disk_ops_t mmc_disk_ops = {
+    .get_info = mmc_get_info,
+    .eject = mmc_eject,
+    .read = mmc_read,
+    .write = mmc_write,
 };
 
-#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
-static struct mmc mmc;
-static struct mmc_config mmc_config = {
-    .spi_cfg = {
-        .pin_cs = MYNEWT_VAL(MMC_SPI_CS_PIN),
-        .freq = MYNEWT_VAL(MMC_SPI_FREQ),
-        .data_order = BUS_SPI_DATA_ORDER_MSB,
-        .mode = BUS_SPI_MODE_0,
-        .node_cfg.bus_name = MYNEWT_VAL(MMC_SPI_BUS_NAME),
-        .node_cfg.lock_timeout_ms = 1000,
+static mmc_disk_t mmc0 = {
+    .disk.ops = &mmc_disk_ops,
+    .disk_info = {
+        .name = "SD0",
     }
 };
-#endif
 
 void
 mmc_pkg_init(void)
 {
-#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
-    if (0 == mmc_create_dev(&mmc, MYNEWT_VAL(MMC_DEV_NAME), &mmc_config)) {
-        if (MYNEWT_VAL(MMC_AUTO_MOUNT)) {
-            os_dev_open(MYNEWT_VAL(MMC_DEV_NAME), 1000, NULL);
-        }
+    int rc;
+
+    if (MYNEWT_VAL_MMC_LED_PIN >= 0) {
+        hal_gpio_init_out(MYNEWT_VAL_MMC_LED_PIN, !MYNEWT_VAL_MMC_LED_ON_VALUE);
     }
+
+#if MYNEWT_VAL(BUS_DRIVER_PRESENT)
+    rc = mmc_create_dev(&mmc0, MYNEWT_VAL(MMC_DEV_NAME), &mmc0_config);
 #else
     struct mmc_spi_cfg spi_cfg = {
-        .clock_mode = HAL_SPI_MODE0,
+        .clock_mode = MYNEWT_VAL_MMC_SPI_CLOCK_MODE,
         .initial_freq_khz = 400,
-        .freq_khz = MYNEWT_VAL(MMC_SPI_FREQ),
+        .freq_khz = MYNEWT_VAL_MMC_SPI_FREQ,
+        .pin_cs = MYNEWT_VAL_MMC_SPI_CS_PIN,
     };
-    mmc_init(MYNEWT_VAL(MMC_SPI_NUM), &spi_cfg, MYNEWT_VAL(MMC_SPI_CS_PIN));
+    rc = mmc_create(&mmc0, MYNEWT_VAL(MMC_SPI_NUM), &spi_cfg);
 #endif
-    if (MYNEWT_VAL(MMC_AUTO_MOUNT)) {
-        uint8_t *sector = malloc(512);
-
-        if (sector == NULL) {
-        } else {
-            /* For now only FAT partition are mounted */
-            if (mmc_read(0, 0, sector, 512) == 0) {
-                /* Check if first partition is FAT */
-                if (sector[450] == 0x0C || sector[450] == 0x07) {
-                    disk_register(MYNEWT_VAL(MMC_DEV_NAME), "fatfs", &mmc_ops);
-                }
-            }
+    if (rc == 0 && MYNEWT_VAL_MMC_AUTO_INIT) {
+        if (mmc_init(&mmc0) == 0) {
+            mmc0.disk_info.block_size = BLOCK_LEN;
+            mmc0.disk_info.block_count = csd_sector_count(mmc0.csd);
+            mmc0.disk_info.present = 1;
+            mn_disk_inserted(&mmc0.disk);
         }
-        free(sector);
     }
 }
diff --git a/hw/drivers/mmc/syscfg.yml b/hw/drivers/mmc/syscfg.yml
index 1c6bfad45..04d8caf35 100644
--- a/hw/drivers/mmc/syscfg.yml
+++ b/hw/drivers/mmc/syscfg.yml
@@ -29,12 +29,46 @@ syscfg.defs:
     MMC_SPI_CS_PIN:
         description: MMC SPI CS pin.
         value: -1
+    MMC_SPI_CLOCK_MODE:
+        description: >
+            MMC SPI clock mode. Mode 0 and 3 should work.
+            Mode 3 can be used in case of pullup on CLK line.
+        value: 0
     MMC_DEV_NAME:
         description: MMC SPI device name for bus driver build.
         value: '"mmc"'
+    MMC_LED_PIN:
+        description: Pin to use to indicate MMC access.
+        value: -1
+    MMC_LED_ON_VALUE:
+        description: Value of MSC_LED_PIN to turn LED on.
+        value: 1
+    MMC_SEND_EXTRA_CLOCKS:
+        description: >
+            Number of bytes to send AFTER CS is deactivated.
+            This can fix problem with some older cards that start
+            to send status with out of sync clock.
+        value: 0
+
     MMC_PKG_SYSINIT_STAGE:
         description: Sysinit stage for MMC package.
-        value: 5
+        value: 200
+    MMC_AUTO_INIT:
+        descritpion: >
+            Initialize disk during startup
+        value: 1
     MMC_AUTO_MOUNT:
         description: Try to mount disk at creation time.
         value: 1
+
+    MMC_LOG_MODULE:
+        description: 'Numeric module ID to use for MMC log messages.'
+        value: 11
+    MMC_LOG_LVL:
+        description: 'Minimum level for the MMC log.'
+        value: 1
+
+syscfg.logs:
+    MMC_LOG:
+        module: MYNEWT_VAL(MMC_LOG_MODULE)
+        level: MYNEWT_VAL(MMC_LOG_LVL)


(mynewt-core) 05/08: fs/fatfs: Rework to use file system api

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kasjer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 9470a663cfc96f670fab8dd264b4aac87fd0f46e
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Sat Jun 21 22:30:17 2025 +0200

    fs/fatfs: Rework to use file system api
    
    This adds file disk listener that can mount fatfs
    disk (like sdcard) if it contains FAT data.
    
    Fixes problem with accessing disk grater then 2GB.
    Previous disk interface (that is now removed) used
    32 bit to address bytes of disk.
    Now disk access uses sectors as it the code for disk.
    
    Further more file name conversion from sd0: to 0: is
    now removed. FATFS driver wants to use 0: volumes
    and mynewt wanted to have sd0:
    Now disk will be mounted as 0: removing need for
    conversion and heap allocations.
    
    Signed-off-by: Jerzy Kasenberg <je...@apache.org>
---
 fs/fatfs/pkg.yml           |   8 +-
 fs/fatfs/src/mynewt_glue.c | 415 ++++++++++++++++++++-------------------------
 fs/fatfs/syscfg.yml        |   6 +
 3 files changed, 190 insertions(+), 239 deletions(-)

diff --git a/fs/fatfs/pkg.yml b/fs/fatfs/pkg.yml
index 01cef770d..6b389f60f 100644
--- a/fs/fatfs/pkg.yml
+++ b/fs/fatfs/pkg.yml
@@ -30,11 +30,11 @@ pkg.deps:
     - "@apache-mynewt-core/util/crc"
     - "@apache-mynewt-core/hw/hal"
     - "@apache-mynewt-core/kernel/os"
-    - "@apache-mynewt-core/test/testutil"
-    - "@apache-mynewt-core/sys/flash_map"
 pkg.req_apis:
     - log
     - stats
 
-pkg.init:
-    fatfs_pkg_init: 'MYNEWT_VAL(FATFS_SYSINIT_STAGE)'
+pkg.whole_archive: true
+
+pkg.cflags:
+    - -Wno-unused-variable
diff --git a/fs/fatfs/src/mynewt_glue.c b/fs/fatfs/src/mynewt_glue.c
index 0fbefeb47..ebaa4d697 100644
--- a/fs/fatfs/src/mynewt_glue.c
+++ b/fs/fatfs/src/mynewt_glue.c
@@ -22,11 +22,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "os/mynewt.h"
+#include <os/mynewt.h>
 #include <modlog/modlog.h>
-#include <hal/hal_flash.h>
 #include <disk/disk.h>
-#include <flash_map/flash_map.h>
 
 #include <fatfs/ff.h>
 #include <fatfs/diskio.h>
@@ -53,17 +51,12 @@ static int fatfs_closedir(struct fs_dir *dir);
 static int fatfs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len,
   char *out_name, uint8_t *out_name_len);
 static int fatfs_dirent_is_dir(const struct fs_dirent *fs_dirent);
-
-#define DRIVE_LEN 4
+static int fatfs_mount(const file_system_t *fs);
+static int fatfs_umount(const file_system_t *fs);
 
 struct fatfs_file {
     struct fs_ops *fops;
-    FIL *file;
-};
-
-struct fatfs_dir {
-    struct fs_ops *fops;
-    FATFS_DIR *dir;
+    FIL fil;
 };
 
 struct fatfs_dirent {
@@ -71,11 +64,10 @@ struct fatfs_dirent {
     FILINFO filinfo;
 };
 
-/* NOTE: to ease memory management of dirent structs, this single static
- * variable holds the latest entry found by readdir. This limits FAT to
- * working on a single thread, single opendir -> closedir cycle.
- */
-static struct fatfs_dirent dirent;
+struct fatfs_dir {
+    struct fatfs_dirent dirent;
+    FATFS_DIR dir;
+};
 
 static struct fs_ops fatfs_ops = {
     .f_open = fatfs_open,
@@ -99,9 +91,19 @@ static struct fs_ops fatfs_ops = {
     .f_dirent_name = fatfs_dirent_name,
     .f_dirent_is_dir = fatfs_dirent_is_dir,
 
-    .f_name = "fatfs"
+    .f_mount = fatfs_mount,
+    .f_umount = fatfs_umount,
 };
 
+typedef struct fat_disk {
+    file_system_t fs;
+    char vol[4];
+    FATFS fatfs;
+    disk_t *disk;
+} fat_disk_t;
+
+static fat_disk_t *fat_vol[_VOLUMES];
+
 int fatfs_to_vfs_error(FRESULT res)
 {
     int rc = FS_EOS;
@@ -171,112 +173,22 @@ int fatfs_to_vfs_error(FRESULT res)
     return rc;
 }
 
-struct mounted_disk {
-    char *disk_name;
-    int disk_number;
-    struct disk_ops *dops;
-
-    SLIST_ENTRY(mounted_disk) sc_next;
-};
-
-static SLIST_HEAD(, mounted_disk) mounted_disks = SLIST_HEAD_INITIALIZER();
-
-static int
-drivenumber_from_disk(char *disk_name)
-{
-    struct mounted_disk *sc;
-    struct mounted_disk *new_disk;
-    int disk_number;
-    FATFS *fs;
-    char path[6];
-
-    disk_number = 0;
-    if (disk_name) {
-        SLIST_FOREACH(sc, &mounted_disks, sc_next) {
-            if (strcmp(sc->disk_name, disk_name) == 0) {
-                return sc->disk_number;
-            }
-            disk_number++;
-        }
-    }
-
-    /* XXX: check for errors? */
-    fs = malloc(sizeof(FATFS));
-    sprintf(path, "%d:", (uint8_t)disk_number);
-    f_mount(fs, path, 1);
-
-    /* FIXME */
-    new_disk = malloc(sizeof(struct mounted_disk));
-    new_disk->disk_name = strdup(disk_name);
-    new_disk->disk_number = disk_number;
-    new_disk->dops = disk_ops_for(disk_name);
-    SLIST_INSERT_HEAD(&mounted_disks, new_disk, sc_next);
-
-    return disk_number;
-}
-
-/**
- * Converts fs path to fatfs path
- *
- * Function changes mmc0:/dir/file.ext to 0:/dir/file.ext
- *
- * @param fs_path
- * @return pointer to allocated memory with fatfs path
- */
-static char *
-fatfs_path_from_fs_path(const char *fs_path)
-{
-    char *disk;
-    int drive_number;
-    char *file_path = NULL;
-    char *fatfs_path = NULL;
-
-    disk = disk_name_from_path(fs_path);
-    if (disk == NULL) {
-        goto err;
-    }
-    drive_number = drivenumber_from_disk(disk);
-    free(disk);
-    file_path = disk_filepath_from_path(fs_path);
-
-    if (file_path == NULL) {
-        goto err;
-    }
-
-    fatfs_path = malloc(strlen(file_path) + 3);
-    if (fatfs_path == NULL) {
-        goto err;
-    }
-    sprintf(fatfs_path, "%d:%s", drive_number, file_path);
-err:
-    free(file_path);
-    return fatfs_path;
-}
-
 static int
 fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file)
 {
     FRESULT res;
-    FIL *out_file = NULL;
     BYTE mode;
     struct fatfs_file *file = NULL;
-    char *fatfs_path = NULL;
     int rc;
 
     FATFS_LOG_DEBUG("Open file %s", path);
 
-    file = malloc(sizeof(struct fatfs_file));
+    file = os_malloc(sizeof(struct fatfs_file));
     if (!file) {
         rc = FS_ENOMEM;
         goto out;
     }
 
-    out_file = malloc(sizeof(FIL));
-    if (!out_file) {
-        rc = FS_ENOMEM;
-        goto out;
-    }
-
     mode = FA_OPEN_EXISTING;
     if (access_flags & FS_ACCESS_READ) {
         mode |= FA_READ;
@@ -292,29 +204,21 @@ fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file)
         mode |= FA_CREATE_ALWAYS;
     }
 
-    fatfs_path = fatfs_path_from_fs_path(path);
-    if (fatfs_path == NULL) {
-        rc = FS_ENOMEM;
-        goto out;
-    }
-    res = f_open(out_file, fatfs_path, mode);
+    res = f_open(&file->fil, path, mode);
     if (res != FR_OK) {
         rc = fatfs_to_vfs_error(res);
         goto out;
     }
 
-    file->file = out_file;
     file->fops = &fatfs_ops;
     *out_fs_file = (struct fs_file *) file;
     rc = FS_EOK;
 
 out:
-    free(fatfs_path);
     if (rc != FS_EOK) {
         FATFS_LOG_ERROR("File %s open failed %d", path, rc);
 
         if (file) free(file);
-        if (out_file) free(out_file);
     } else {
         FATFS_LOG_DEBUG("File %s opened %p", path, *out_fs_file);
     }
@@ -324,15 +228,12 @@ out:
 static int
 fatfs_close(struct fs_file *fs_file)
 {
-    FRESULT res = FR_OK;
-    FIL *file = ((struct fatfs_file *) fs_file)->file;
+    struct fatfs_file *fat_file = (struct fatfs_file *)fs_file;
+    FRESULT res;
 
-    FATFS_LOG_DEBUG("Open file %p", fs_file);
+    FATFS_LOG_DEBUG("Close file %p", fs_file);
 
-    if (file != NULL) {
-        res = f_close(file);
-        free(file);
-    }
+    res = f_close(&fat_file->fil);
 
     free(fs_file);
     return fatfs_to_vfs_error(res);
@@ -342,7 +243,7 @@ static int
 fatfs_seek(struct fs_file *fs_file, uint32_t offset)
 {
     FRESULT res;
-    FIL *file = ((struct fatfs_file *) fs_file)->file;
+    FIL *file = &((struct fatfs_file *)fs_file)->fil;
 
     FATFS_LOG_DEBUG("File %p seek %u", fs_file, offset);
 
@@ -354,7 +255,7 @@ static uint32_t
 fatfs_getpos(const struct fs_file *fs_file)
 {
     uint32_t offset;
-    FIL *file = ((struct fatfs_file *) fs_file)->file;
+    FIL *file = &((struct fatfs_file *)fs_file)->fil;
 
     offset = (uint32_t) f_tell(file);
     return offset;
@@ -363,7 +264,7 @@ fatfs_getpos(const struct fs_file *fs_file)
 static int
 fatfs_file_len(const struct fs_file *fs_file, uint32_t *out_len)
 {
-    FIL *file = ((struct fatfs_file *) fs_file)->file;
+    FIL *file = &((struct fatfs_file *)fs_file)->fil;
 
     *out_len = (uint32_t) f_size(file);
 
@@ -377,7 +278,7 @@ fatfs_read(struct fs_file *fs_file, uint32_t len, void *out_data,
            uint32_t *out_len)
 {
     FRESULT res;
-    FIL *file = ((struct fatfs_file *) fs_file)->file;
+    FIL *file = &((struct fatfs_file *)fs_file)->fil;
     UINT uint_len;
 
     FATFS_LOG_DEBUG("File %p read %u", fs_file, len);
@@ -392,7 +293,7 @@ fatfs_write(struct fs_file *fs_file, const void *data, int len)
 {
     FRESULT res;
     UINT out_len;
-    FIL *file = ((struct fatfs_file *) fs_file)->file;
+    FIL *file = &((struct fatfs_file *)fs_file)->fil;
 
     FATFS_LOG_DEBUG("File %p write %u", fs_file, len);
 
@@ -407,7 +308,7 @@ static int
 fatfs_flush(struct fs_file *fs_file)
 {
     FRESULT res;
-    FIL *file = ((struct fatfs_file *)fs_file)->file;
+    FIL *file = &((struct fatfs_file *)fs_file)->fil;
 
     FATFS_LOG_DEBUG("Flush %p", fs_file);
 
@@ -420,17 +321,10 @@ static int
 fatfs_unlink(const char *path)
 {
     FRESULT res;
-    char *fatfs_path;
 
     FATFS_LOG_INFO("Unlink %s", path);
 
-    fatfs_path = fatfs_path_from_fs_path(path);
-
-    if (fatfs_path == NULL) {
-        return FS_ENOMEM;
-    }
-    res = f_unlink(fatfs_path);
-    free(fatfs_path);
+    res = f_unlink(path);
 
     return fatfs_to_vfs_error(res);
 }
@@ -439,23 +333,10 @@ static int
 fatfs_rename(const char *from, const char *to)
 {
     FRESULT res;
-    char *fatfs_src_path;
-    char *fatfs_dst_path;
 
     FATFS_LOG_INFO("Rename %s to %s", from, to);
 
-    fatfs_src_path = fatfs_path_from_fs_path(from);
-    fatfs_dst_path = fatfs_path_from_fs_path(to);
-
-    if (fatfs_src_path == NULL || fatfs_dst_path == NULL) {
-        free(fatfs_src_path);
-        free(fatfs_dst_path);
-        return FS_ENOMEM;
-    }
-
-    res = f_rename(fatfs_src_path, fatfs_dst_path);
-    free(fatfs_src_path);
-    free(fatfs_dst_path);
+    res = f_rename(from, to);
 
     return fatfs_to_vfs_error(res);
 }
@@ -464,17 +345,10 @@ static int
 fatfs_mkdir(const char *path)
 {
     FRESULT res;
-    char *fatfs_path;
 
     FATFS_LOG_INFO("Mkdir %s", path);
 
-    fatfs_path = fatfs_path_from_fs_path(path);
-
-    if (fatfs_path == NULL) {
-        return FS_ENOMEM;
-    }
-
-    res = f_mkdir(fatfs_path);
+    res = f_mkdir(path);
     return fatfs_to_vfs_error(res);
 }
 
@@ -482,45 +356,34 @@ static int
 fatfs_opendir(const char *path, struct fs_dir **out_fs_dir)
 {
     FRESULT res;
-    FATFS_DIR *out_dir = NULL;
     struct fatfs_dir *dir = NULL;
-    char *fatfs_path = NULL;
     int rc;
 
-    dir = malloc(sizeof(struct fatfs_dir));
+    dir = os_malloc(sizeof(struct fatfs_dir));
     if (!dir) {
         rc = FS_ENOMEM;
         goto out;
     }
+    dir->dirent.fops = &fatfs_ops;
 
-    out_dir = malloc(sizeof(FATFS_DIR));
-    if (!out_dir) {
-        rc = FS_ENOMEM;
-        goto out;
-    }
-
-    fatfs_path = fatfs_path_from_fs_path(path);
-
-    res = f_opendir(out_dir, fatfs_path);
+    res = f_opendir(&dir->dir, path);
     if (res != FR_OK) {
         rc = fatfs_to_vfs_error(res);
         goto out;
     }
 
-    dir->dir = out_dir;
-    dir->fops = &fatfs_ops;
     *out_fs_dir = (struct fs_dir *)dir;
     rc = FS_EOK;
 
     FATFS_LOG_INFO("Open dir %s -> %p", path, *out_fs_dir);
 
 out:
-    free(fatfs_path);
     if (rc != FS_EOK) {
         FATFS_LOG_ERROR("Open dir %s failed %d", path, rc);
 
-        if (dir) free(dir);
-        if (out_dir) free(out_dir);
+        if (dir) {
+            os_free(dir);
+        }
     }
     return rc;
 }
@@ -529,18 +392,18 @@ static int
 fatfs_readdir(struct fs_dir *fs_dir, struct fs_dirent **out_fs_dirent)
 {
     FRESULT res;
-    FATFS_DIR *dir = ((struct fatfs_dir *) fs_dir)->dir;
+    struct fatfs_dir *fat_dir = ((struct fatfs_dir *)fs_dir);
+    FATFS_DIR *dir = &fat_dir->dir;
 
     FATFS_LOG_DEBUG("Read dir %p", fs_dir);
 
-    dirent.fops = &fatfs_ops;
-    res = f_readdir(dir, &dirent.filinfo);
+    res = f_readdir(dir, &fat_dir->dirent.filinfo);
     if (res != FR_OK) {
         return fatfs_to_vfs_error(res);
     }
 
-    *out_fs_dirent = (struct fs_dirent *) &dirent;
-    if (!dirent.filinfo.fname[0]) {
+    *out_fs_dirent = (struct fs_dirent *)&fat_dir->dirent;
+    if (!fat_dir->dirent.filinfo.fname[0]) {
         return FS_ENOENT;
     }
     return FS_EOK;
@@ -550,13 +413,13 @@ static int
 fatfs_closedir(struct fs_dir *fs_dir)
 {
     FRESULT res;
-    FATFS_DIR *dir = ((struct fatfs_dir *) fs_dir)->dir;
+    FATFS_DIR *dir = &((struct fatfs_dir *)fs_dir)->dir;
 
     FATFS_LOG_INFO("Close dir %p", fs_dir);
 
     res = f_closedir(dir);
-    free(dir);
-    free(fs_dir);
+
+    os_free(fs_dir);
     return fatfs_to_vfs_error(res);
 }
 
@@ -585,6 +448,30 @@ fatfs_dirent_is_dir(const struct fs_dirent *fs_dirent)
     return filinfo->fattrib & AM_DIR;
 }
 
+static int
+fatfs_mount(const file_system_t *fs)
+{
+    int rc;
+    fat_disk_t *fat_disk = (fat_disk_t *)fs;
+
+    /* Pass to FAT driver */
+    rc = f_mount(&fat_disk->fatfs, fat_disk->vol, 0);
+
+    return rc;
+}
+
+static int
+fatfs_umount(const file_system_t *fs)
+{
+    int rc;
+    fat_disk_t *fat_disk = (fat_disk_t *)fs;
+
+    /* Pass to FAT driver */
+    rc = f_mount(NULL, fat_disk->vol, 0);
+
+    return rc;
+}
+
 DSTATUS
 disk_initialize(BYTE pdrv)
 {
@@ -599,67 +486,40 @@ disk_status(BYTE pdrv)
     return RES_OK;
 }
 
-static struct disk_ops *dops_from_handle(BYTE pdrv)
-{
-    struct mounted_disk *sc;
-
-    SLIST_FOREACH(sc, &mounted_disks, sc_next) {
-        if (sc->disk_number == pdrv) {
-            return sc->dops;
-        }
-    }
-
-    return NULL;
-}
-
 DRESULT
 disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
 {
     int rc;
-    uint32_t address;
-    uint32_t num_bytes;
-    struct disk_ops *dops;
-
-    /* NOTE: safe to assume sector size as 512 for now, see ffconf.h */
-    address = (uint32_t) sector * 512;
-    num_bytes = (uint32_t) count * 512;
-
-    dops = dops_from_handle(pdrv);
-    if (dops == NULL) {
-        return STA_NOINIT;
-    }
+    struct fat_disk *fat_disk = fat_vol[pdrv];
 
-    rc = dops->read(pdrv, address, (void *) buff, num_bytes);
-    if (rc < 0) {
-        return STA_NOINIT;
+    if (fat_disk != NULL) {
+        rc = mn_disk_read(fat_disk->disk, sector, buff, count);
+        if (rc != 0) {
+            rc = FR_NOT_READY;
+        }
+    } else {
+        rc = FR_NOT_READY;
     }
 
-    return RES_OK;
+    return rc;
 }
 
 DRESULT
 disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
 {
     int rc;
-    uint32_t address;
-    uint32_t num_bytes;
-    struct disk_ops *dops;
-
-    /* NOTE: safe to assume sector size as 512 for now, see ffconf.h */
-    address = (uint32_t) sector * 512;
-    num_bytes = (uint32_t) count * 512;
-
-    dops = dops_from_handle(pdrv);
-    if (dops == NULL) {
-        return STA_NOINIT;
-    }
+    struct fat_disk *fat_disk = fat_vol[pdrv];
 
-    rc = dops->write(pdrv, address, (const void *) buff, num_bytes);
-    if (rc < 0) {
-        return STA_NOINIT;
+    if (fat_disk != NULL) {
+        rc = mn_disk_write(fat_disk->disk, sector, buff, count);
+        if (rc != 0) {
+            rc = FR_NOT_READY;
+        }
+    } else {
+        rc = FR_NOT_READY;
     }
 
-    return RES_OK;
+    return rc;
 }
 
 DRESULT
@@ -742,11 +602,96 @@ ff_wtoupper(WCHAR chr)
     return toupper(chr);
 }
 
-void
-fatfs_pkg_init(void)
+#if MYNEWT_VAL_FATFS_AUTO_MOUNT_DISKS
+int
+fatfs_disk_added(struct disk_listener *listener, struct disk *disk)
 {
-    /* Ensure this function only gets called by sysinit. */
-    SYSINIT_ASSERT_ACTIVE();
+    fat_disk_t *fat_disk;
+    int i;
+    int rc;
+
+    for (i = 0; i < _VOLUMES; ++i) {
+        if (fat_vol[i] == NULL) {
+            break;
+        }
+    }
+    if (i >= _VOLUMES) {
+        fat_disk = NULL;
+        FATFS_LOG_ERROR("Can mount additional volumes");
+        goto end;
+    }
+    fat_disk = os_malloc(sizeof(*fat_disk));
+
+    if (fat_disk == NULL) {
+        FATFS_LOG_ERROR("No enough heap for FAT file system");
+        goto end;
+    }
+
+    if (mn_disk_read(disk, 0, fat_disk->fatfs.win, 1) == 0) {
+        disk_info_t di;
+        uint8_t fs_type = fat_disk->fatfs.win[450];
+        mn_disk_info_get(disk, &di);
+
+        /* Check if first partition is FAT */
+        if (fs_type == 0x0C || fs_type == 0x0B || (_FS_EXFAT && fs_type == 0x07)) {
+            fat_disk->disk = disk;
+            fat_disk->fs.ops = &fatfs_ops;
+            fat_disk->fs.name = "fatfs";
+            fat_disk->vol[0] = '0' + i;
+            fat_disk->vol[1] = ':';
+            fat_disk->vol[2] = '\0';
+
+            /* Associate in mynewt */
+            rc = fs_mount(&fat_disk->fs, fat_disk->vol);
+            if (rc != 0) {
+                FATFS_LOG_ERROR("Can't mount FAT file system");
+            } else {
+                fat_vol[i] = fat_disk;
+                /* Disk successfully mounted, prevent from being freed */
+                FATFS_LOG_INFO("Mounted FAT partition from %s at %s", di.name,
+                               fat_disk->vol);
+                fat_disk = NULL;
+            }
+        } else {
+            FATFS_LOG_INFO("Disk %s not with FAT file system", di.name);
+        }
+    }
+end:
+    if (fat_disk) {
+        os_free(fat_disk);
+    }
+    return 0;
+}
 
-    fs_register(&fatfs_ops);
+int
+fatfs_disk_removed(struct disk_listener *listener, struct disk *disk)
+{
+    int i;
+    int rc = FS_EINVAL;
+    struct fat_disk *fat_disk;
+
+    for (i = 0; i < _VOLUMES; ++i) {
+        fat_disk = fat_vol[i];
+        if (fat_disk->disk == disk) {
+            fs_unmount_file_system(&fat_disk->fs);
+            fat_vol[i] = NULL;
+            os_free(fat_disk);
+            rc = 0;
+            break;
+        }
+    }
+    return rc;
 }
+
+const disk_listener_ops_t fatfs_disk_listener_ops = {
+    .disk_added = fatfs_disk_added,
+    .disk_removed = fatfs_disk_removed,
+};
+
+disk_listener_t fatfs_disk_listener = {
+    .ops = &fatfs_disk_listener_ops,
+};
+
+DISK_LISTENER(fatfs_disk_listener_ptr, fatfs_disk_listener)
+
+#endif
diff --git a/fs/fatfs/syscfg.yml b/fs/fatfs/syscfg.yml
index 66035279b..93c85f947 100644
--- a/fs/fatfs/syscfg.yml
+++ b/fs/fatfs/syscfg.yml
@@ -48,6 +48,12 @@ syscfg.defs:
             Timout for locking file system object.
         value: 1000
 
+    FATFS_AUTO_MOUNT_DISKS:
+        description: >
+            If 1 package tries to read every disks that is inserted
+            and if it's FAT disk, mounts it automatically.
+        value: 1
+
     FATFS_LOG_MODULE:
         description: 'Numeric module ID to use for FATFS log messages.'
         value: 253