extmod/fsusermount: Change block protocol to support ioctl method.

The new block protocol is:
- readblocks(self, n, buf)
- writeblocks(self, n, buf)
- ioctl(self, cmd, arg)

The new ioctl method handles the old sync and count methods, as well as
a new "get sector size" method.

The old protocol is still supported, and used if the device doesn't have
the ioctl method.
This commit is contained in:
Damien George 2016-02-09 14:28:50 +00:00
parent 3846fd56c1
commit c33ad60a67
4 changed files with 67 additions and 18 deletions

View File

@ -76,8 +76,15 @@ STATIC mp_obj_t fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_
// load block protocol methods // load block protocol methods
mp_load_method(device, MP_QSTR_readblocks, vfs->readblocks); mp_load_method(device, MP_QSTR_readblocks, vfs->readblocks);
mp_load_method_maybe(device, MP_QSTR_writeblocks, vfs->writeblocks); mp_load_method_maybe(device, MP_QSTR_writeblocks, vfs->writeblocks);
mp_load_method_maybe(device, MP_QSTR_sync, vfs->sync); mp_load_method_maybe(device, MP_QSTR_ioctl, vfs->u.ioctl);
mp_load_method(device, MP_QSTR_count, vfs->count); if (vfs->u.ioctl[0] != MP_OBJ_NULL) {
// device supports new block protocol, so indicate it
vfs->u.old.count[1] = MP_OBJ_SENTINEL;
} else {
// no ioctl method, so assume the device uses the old block protocol
mp_load_method_maybe(device, MP_QSTR_sync, vfs->u.old.sync);
mp_load_method(device, MP_QSTR_count, vfs->u.old.count);
}
// Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL.
// User can specify read-only device by: // User can specify read-only device by:

View File

@ -29,8 +29,15 @@ typedef struct _fs_user_mount_t {
mp_uint_t len; mp_uint_t len;
mp_obj_t readblocks[4]; mp_obj_t readblocks[4];
mp_obj_t writeblocks[4]; mp_obj_t writeblocks[4];
// new protocol uses just ioctl, old uses sync (optional) and count
// if ioctl[3]=count[1]=MP_OBJ_SENTINEL then we have the new protocol, else old
union {
mp_obj_t ioctl[4];
struct {
mp_obj_t sync[2]; mp_obj_t sync[2];
mp_obj_t count[2]; mp_obj_t count[2];
} old;
} u;
FATFS fatfs; FATFS fatfs;
} fs_user_mount_t; } fs_user_mount_t;

View File

@ -675,6 +675,7 @@ Q(readonly)
Q(mkfs) Q(mkfs)
Q(readblocks) Q(readblocks)
Q(writeblocks) Q(writeblocks)
Q(ioctl)
Q(sync) Q(sync)
Q(count) Q(count)
#endif #endif

View File

@ -39,6 +39,12 @@
#include "sdcard.h" #include "sdcard.h"
#include "extmod/fsusermount.h" #include "extmod/fsusermount.h"
// constants for block protocol ioctl
//#define BP_IOCTL_INIT (1) // unused
//#define BP_IOCTL_DEINIT (2) // unused
#define BP_IOCTL_SYNC (3)
#define BP_IOCTL_SEC_COUNT (4)
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Initialize a Drive */ /* Initialize a Drive */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -242,30 +248,58 @@ DRESULT disk_ioctl (
break; break;
#endif #endif
case PD_USER: case PD_USER: {
if (MP_STATE_PORT(fs_user_mount) == NULL) { fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount);
if (vfs == NULL) {
// nothing mounted // nothing mounted
return RES_ERROR; return RES_ERROR;
} }
if (vfs->u.old.count[1] == MP_OBJ_SENTINEL) {
// new protocol with ioctl
switch (cmd) { switch (cmd) {
case CTRL_SYNC: case CTRL_SYNC:
if (MP_STATE_PORT(fs_user_mount)->sync[0] != MP_OBJ_NULL) { vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC);
mp_call_method_n_kw(0, 0, MP_STATE_PORT(fs_user_mount)->sync); vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
} mp_call_method_n_kw(2, 0, vfs->u.ioctl);
return RES_OK; vfs->u.ioctl[3] = MP_OBJ_SENTINEL; // indicate new protocol
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // high-level sector erase size in units of the small (512) bl
return RES_OK; return RES_OK;
case GET_SECTOR_COUNT: { case GET_SECTOR_COUNT: {
mp_obj_t ret = mp_call_method_n_kw(0, 0, MP_STATE_PORT(fs_user_mount)->count); vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT);
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
*((DWORD*)buff) = mp_obj_get_int(ret); *((DWORD*)buff) = mp_obj_get_int(ret);
vfs->u.ioctl[3] = MP_OBJ_SENTINEL; // indicate new protocol
return RES_OK;
}
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // erase block size in units of sector size
return RES_OK;
}
} else {
// old protocol with sync and count
switch (cmd) {
case CTRL_SYNC:
if (vfs->u.old.sync[0] != MP_OBJ_NULL) {
mp_call_method_n_kw(0, 0, vfs->u.old.sync);
}
return RES_OK;
case GET_SECTOR_COUNT: {
mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
*((DWORD*)buff) = mp_obj_get_int(ret);
return RES_OK;
}
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // erase block size in units of sector size
return RES_OK; return RES_OK;
} }
} }
break; break;
} }
}
return RES_PARERR; return RES_PARERR;
} }