欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

mmc_spi.c

开放源码实时操作系统源码.
C
第 1 页 / 共 4 页
字号:
    }
    return false;
}

// ----------------------------------------------------------------------------

// No hardware initialization is performed here. Even if a card is
// currently plugged in it may get removed before it gets mounted, so
// there is no point looking at the card here. It is still necessary
// to invoke the callback init function so that higher-level code gets
// a chance to do its bit.
static cyg_bool
mmc_spi_disk_init(struct cyg_devtab_entry* tab)
{
    disk_channel*   chan    = (disk_channel*) tab->priv;
    MMC_SPI_INIT_FF_DATA();
    return (*chan->callbacks->disk_init)(tab);
}

// lookup() is called during a mount() operation, so this is the right
// place to check whether or not there is a card.

static char*
mmc_spi_disk_lookup_itoa(cyg_uint32 num, char* where)
{
    if (0 == num) {
        *where++ = '0';
    } else {
        char local[10];  // 2^32 just fits into 10 places
        int  index = 9;
        while (num > 0) {
            local[index--] = (num % 10) + '0';
            num /= 10;
        }
        for (index += 1; index < 10; index++) {
            *where++ = local[index];
        }
    }
    return where;
}

static Cyg_ErrNo
mmc_spi_disk_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry *sub_tab, const char* name)
{
    disk_channel*               chan    = (disk_channel*) (*tab)->priv;
    cyg_mmc_spi_disk_info_t*    disk    = (cyg_mmc_spi_disk_info_t*) chan->dev_priv;
    Cyg_ErrNo                   result;

    DEBUG2("mmc_spi_disk_lookup(): target name=%s\n", name );
    DEBUG2("                     : device name=%s dep_name=%s\n", tab[0]->name, tab[0]->dep_name );
    DEBUG2("                     : sub    name=%s dep_name=%s\n", sub_tab->name, sub_tab->dep_name );

    if (disk->mmc_connected) {
        // There was a card plugged in last time we looked. Is it still there?
        if (mmc_spi_disk_changed(disk)) {
            // The old card is gone. Either there is no card plugged in, or
            // it has been replaced with a different one. If the latter the
            // existing mounts must be removed before anything sensible
            // can be done.
            disk->mmc_connected = false;
            (*chan->callbacks->disk_disconnected)(chan);
            if (0 != chan->info->mounts) {
                return -ENODEV;
            }
        }
    }

    if ((0 != chan->info->mounts) && !disk->mmc_connected) {
        // There are still mount points to an old card. We cannot accept
        // new mount requests until those have been cleaned out.
        return -ENODEV;
    }

    if (!disk->mmc_connected) {
        cyg_disk_identify_t ident;
        cyg_uint32          id_data;
        char*               where;
        int                 i;
        
        // The world is consistent and the higher-level code does not
        // know anything about the current card, if any. Is there a
        // card?
        result = mmc_spi_check_for_disk(disk);
        if (ENOERR != result) {
            return result;
        }
        // A card has been found. Tell the higher-level code about it.
        // This requires an identify structure, although it is not
        // entirely clear what purpose that serves.
        disk->mmc_connected = true;
        // Serial number, up to 20 characters; The CID register contains
        // various fields which can be used for this.
        where   = &(ident.serial[0]);
        id_data = disk->mmc_id.cid_data[0];   // 1-byte manufacturer id -> 3 chars, 17 left
        where   = mmc_spi_disk_lookup_itoa(id_data, where);
        id_data = (disk->mmc_id.cid_data[1] << 8) + disk->mmc_id.cid_data[2]; // 2-byte OEM ID, 5 chars, 12 left
        where   = mmc_spi_disk_lookup_itoa(id_data, where);
        id_data = (disk->mmc_id.cid_data[10] << 24) + (disk->mmc_id.cid_data[11] << 16) +
            (disk->mmc_id.cid_data[12] << 8) + disk->mmc_id.cid_data[13];
        where   = mmc_spi_disk_lookup_itoa(id_data, where); // 4-byte OEM ID, 10 chars, 2 left
        // And terminate the string with a couple of places to spare.
        *where = '\0';

        // Firmware revision number. There is a one-byte product
        // revision number in the CID, BCD-encoded
        id_data = disk->mmc_id.cid_data[9] >> 4;
        if (id_data <= 9) {
            ident.firmware_rev[0] = id_data + '0';
        } else {
            ident.firmware_rev[0] = id_data - 10 + 'A';
        }
        id_data = disk->mmc_id.cid_data[9] & 0x0F;
        if (id_data <= 9) {
            ident.firmware_rev[1] = id_data + '0';
        } else {
            ident.firmware_rev[1] = id_data - 10 + 'A';
        }
        ident.firmware_rev[2]   = '\0';
        
        // Model number. There is a six-byte product name in the CID.
        for (i = 0; i < 6; i++) {
            if ((disk->mmc_id.cid_data[i + 3] >= 0x20) && (disk->mmc_id.cid_data[i+3] <= 0x7E)) {
                ident.model_num[i] = disk->mmc_id.cid_data[i + 3];
            } else {
                break;
            }
        }
        ident.model_num[i] = '\0';

        // We don't have no cylinders, heads, or sectors, but
        // higher-level code may interpret partition data using C/H/S
        // addressing rather than LBA. Hence values for some of these
        // settings were calculated above.
        ident.cylinders_num     = 1;
        ident.heads_num         = disk->mmc_heads_per_cylinder;
        ident.sectors_num       = disk->mmc_sectors_per_head;
        ident.lba_sectors_num   = disk->mmc_block_count;
        ident.phys_block_size   = disk->mmc_write_block_length/512;
        ident.max_transfer      = disk->mmc_write_block_length;

        DEBUG1("Calling disk_connected(): serial %s, firmware %s, model %s, heads %d, sectors %d, lba_sectors_num %d, phys_block_size %d\n", \
               ident.serial, ident.firmware_rev, ident.model_num, ident.heads_num, ident.sectors_num,
               ident.lba_sectors_num, ident.phys_block_size);
        (*chan->callbacks->disk_connected)(*tab, &ident);

        // We now have a valid card and higher-level code knows about it. Fall through.
    }

    // And leave it to higher-level code to finish the lookup, taking
    // into accounts partitions etc.
    return (*chan->callbacks->disk_lookup)(tab, sub_tab, name);
}

static Cyg_ErrNo
mmc_spi_disk_read(disk_channel* chan, void* buf_arg, cyg_uint32 blocks, cyg_uint32 first_block)
{
    cyg_mmc_spi_disk_info_t*    disk    = (cyg_mmc_spi_disk_info_t*) chan->dev_priv;
    cyg_uint32                  i;
    cyg_uint8*                  buf = (cyg_uint8*) buf_arg;
    Cyg_ErrNo                   code = ENOERR;
    
    DEBUG1("mmc_spi_disk_read(): first block %d, buf %p, len %lu blocks (%lu bytes)\n",
           first_block, buf, (unsigned long)blocks, (unsigned long)blocks*512);

    if (! disk->mmc_connected) {
        return -ENODEV;
    }
    if ((first_block + blocks) >= disk->mmc_block_count) {
        return -EINVAL;
    }

    for (i = 0; (i < blocks) && (ENOERR == code); i++) {
        code = mmc_spi_read_disk_block(disk, buf, first_block + i, false);
        buf += MMC_SPI_BLOCK_SIZE;
    }
    return code;
}

static Cyg_ErrNo
mmc_spi_disk_write(disk_channel* chan, const void* buf_arg, cyg_uint32 blocks, cyg_uint32 first_block)
{
    cyg_mmc_spi_disk_info_t*    disk    = (cyg_mmc_spi_disk_info_t*) chan->dev_priv;
    cyg_uint32                  i;
    const cyg_uint8*            buf = (cyg_uint8*) buf_arg;
    Cyg_ErrNo                   code = ENOERR;

    DEBUG1("mmc_spi_disk_write(): first block %d, buf %p, len %lu blocks (%lu bytes)\n",
           first_block, buf, (unsigned long)blocks, (unsigned long)blocks*512);

    if (! disk->mmc_connected) {
        return -ENODEV;
    }
    if (disk->mmc_read_only) {
        return -EROFS;
    }
    if ((first_block + blocks) >= disk->mmc_block_count) {
        return -EINVAL;
    }

    for (i = 0; (i < blocks) && (ENOERR == code); i++) {
        code = mmc_spi_write_disk_block(disk, buf, first_block + i);
        buf += MMC_SPI_BLOCK_SIZE;
    }
    return code;
}

// get_config() and set_config(). There are no supported get_config() operations
// at this time.
static Cyg_ErrNo
mmc_spi_disk_get_config(disk_channel* chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
{
    CYG_UNUSED_PARAM(disk_channel*, chan);
    CYG_UNUSED_PARAM(cyg_uint32, key);
    CYG_UNUSED_PARAM(const void*, buf);
    CYG_UNUSED_PARAM(cyg_uint32*, len);
    
    return -EINVAL;
}

static Cyg_ErrNo
mmc_spi_disk_set_config(disk_channel* chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
{
    Cyg_ErrNo                   result  = ENOERR;
    cyg_mmc_spi_disk_info_t*    disk    = (cyg_mmc_spi_disk_info_t*) chan->dev_priv;

    switch(key) {
      case CYG_IO_SET_CONFIG_DISK_MOUNT:
        // There will have been a successful lookup(), so there's
        // little point in checking the disk again.
        break;

      case CYG_IO_SET_CONFIG_DISK_UMOUNT:
        if (0 == chan->info->mounts) {
            // If this is the last unmount of the card, mark it as
            // disconnected. If the user then removes the card and
            // plugs in a new one everything works cleanly. Also
            // reset the SPI device's clockrate.
            disk->mmc_connected = false;
            mmc_spi_restore_baud(disk);
            result = (chan->callbacks->disk_disconnected)(chan);
        }
        break;
    }

    return result;
}

// ----------------------------------------------------------------------------
// And finally the data structures that define this disk. Some of this
// should be moved into an exported header file so that applications can
// define additional disks.
//
// It is not obvious why there are quite so many structures. Apart
// from the devtab entries there are no tables involved, so there is
// no need to keep everything the same size. The cyg_disk_info_t could
// be the common part of a h/w info_t. The channel structure is
// redundant and its fields could be merged into the cyg_disk_info_t
// structure. That would leave a devtab entry, a disk info structure
// (h/w specific but with a common base), and a disk controller
// structure (ditto).

DISK_FUNS(cyg_mmc_spi_disk_funs,
          mmc_spi_disk_read,
          mmc_spi_disk_write,
          mmc_spi_disk_get_config,
          mmc_spi_disk_set_config
          );

static cyg_mmc_spi_disk_info_t cyg_mmc_spi_disk0_hwinfo = {
    .mmc_spi_dev        = &cyg_spi_mmc_dev0,
#ifdef MMC_SPI_BACKGROUND_WRITES    
    .mmc_writing        = 0,
#endif    
    .mmc_connected      = 0
};

// No h/w controller structure is needed, but the address of the
// second argument is taken anyway.
DISK_CONTROLLER(cyg_mmc_spi_disk_controller_0, cyg_mmc_spi_disk0_hwinfo);

DISK_CHANNEL(cyg_mmc_spi_disk0_channel,
             cyg_mmc_spi_disk_funs,
             cyg_mmc_spi_disk0_hwinfo,
             cyg_mmc_spi_disk_controller_0,
             true,                            /* MBR support */
             1                                /* Number of partitions supported */
             );
             
BLOCK_DEVTAB_ENTRY(cyg_mmc_spi_disk0_devtab_entry,
                   CYGDAT_DEVS_DISK_MMC_SPI_DISK0_NAME,
                   0,
                   &cyg_io_disk_devio,
                   &mmc_spi_disk_init,
                   &mmc_spi_disk_lookup,
                   &cyg_mmc_spi_disk0_channel);

// EOF mmc_spi.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -