⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 disk.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 2 页
字号:
    
    D(("disk disconnected\n")); 

    return ENOERR;    
}
    
// ---------------------------------------------------------------------------

static Cyg_ErrNo
disk_lookup(struct cyg_devtab_entry **tab,
            struct cyg_devtab_entry  *sub_tab,
            const char *name)
{
    disk_channel    *chan = (disk_channel *) (*tab)->priv;
    cyg_disk_info_t *info = chan->info;
    struct cyg_devtab_entry *new_tab;
    disk_channel            *new_chan;
    int dev_num;
    
    if (!info->connected)
        return -EINVAL;

    dev_num = 0;

    while ('\0' != *name)
    {
        if (*name < '0' || *name > '9')
            return -EINVAL;

        dev_num = 10 * dev_num + (*name - '0');
        name++;
    }
   
    if (dev_num > info->partitions_num)
        return -EINVAL;

    D(("disk lookup dev number = %d\n", dev_num)); 

    if (0 == dev_num)
    {
        // 0 is the root device number
        return ENOERR; 
    }
    if (0x00 == info->partitions[dev_num-1].type)
    {
        D(("disk NO partition for dev\n")); 
        return -EINVAL;
    }

    new_tab  = &chan->pdevs_dev[dev_num-1];
    new_chan = &chan->pdevs_chan[dev_num-1];
    
    // copy device data from parent
    *new_tab  = **tab; 
    *new_chan = *chan;

    new_tab->priv = (void *)new_chan;

    // set partition ptr
    new_chan->partition = &info->partitions[dev_num-1];

    // return device tab 
    *tab = new_tab;
        
    return ENOERR;
}

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

static Cyg_ErrNo 
disk_bread(cyg_io_handle_t  handle, 
           void            *buf, 
           cyg_uint32      *len,  // In blocks
           cyg_uint32       pos)  // In blocks
{
    cyg_devtab_entry_t *t    = (cyg_devtab_entry_t *) handle;
    disk_channel       *chan = (disk_channel *) t->priv;
    disk_controller    *ctlr = chan->controller;
    disk_funs          *funs = chan->funs;
    cyg_disk_info_t    *info = chan->info;
    cyg_uint32  size = *len;
    cyg_uint8  *bbuf = (cyg_uint8  *)buf;
    Cyg_ErrNo   res  = ENOERR;
    cyg_uint32  last;

    cyg_drv_mutex_lock( &ctlr->lock );

    while( ctlr->busy )
        cyg_drv_cond_wait( &ctlr->queue );

    if (info->connected && chan->valid)
    {
        ctlr->busy = true;
    
        if (NULL != chan->partition)
        {
            pos += chan->partition->start;
            last = chan->partition->end;
        }
        else
        {
            last = info->blocks_num-1;
        }
 
        D(("disk read block=%d len=%d buf=%p\n", pos, *len, buf));

        while( size > 0 )
        {
            cyg_uint32 tfr = size;
            
            if (pos > last)
            {
                res = -EIO;
                break;
            }

            if( tfr > info->ident.max_transfer )
                tfr = info->ident.max_transfer;
            
            ctlr->result = -EWOULDBLOCK;

            cyg_drv_dsr_lock();
            
            res = (funs->read)(chan, (void*)bbuf, tfr, pos);

            if( res == -EWOULDBLOCK )
            {
                // If the driver replys EWOULDBLOCK, then the transfer is
                // being handled asynchronously and when it is finished it
                // will call disk_transfer_done(). This will wake us up here
                // to continue.

                while( ctlr->result == -EWOULDBLOCK )
                    cyg_drv_cond_wait( &ctlr->async );

                res = ctlr->result;
            }

            cyg_drv_dsr_unlock();
            
            if (ENOERR != res)
                goto done;

            if (!info->connected)
            {
                res = -EINVAL;
                goto done;
            }

            bbuf        += tfr * info->block_size;
            pos         += tfr;
            size        -= tfr;
        }

        ctlr->busy = false;
        cyg_drv_cond_signal( &ctlr->queue );
    }
    else
        res = -EINVAL;

done:
    
    cyg_drv_mutex_unlock( &ctlr->lock );
#ifdef CYGPKG_KERNEL
    cyg_thread_yield();
#endif
    
    *len -= size;
    return res;
}

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

static Cyg_ErrNo 
disk_bwrite(cyg_io_handle_t  handle, 
            const void      *buf, 
            cyg_uint32      *len,   // In blocks
            cyg_uint32       pos)   // In blocks
{
    cyg_devtab_entry_t *t    = (cyg_devtab_entry_t *) handle;
    disk_channel       *chan = (disk_channel *) t->priv;
    disk_controller    *ctlr = chan->controller;    
    disk_funs          *funs = chan->funs;
    cyg_disk_info_t    *info = chan->info;
    cyg_uint32  size = *len;
    cyg_uint8  *bbuf = (cyg_uint8 * const) buf;
    Cyg_ErrNo   res  = ENOERR;
    cyg_uint32  last;

    cyg_drv_mutex_lock( &ctlr->lock );

    while( ctlr->busy )
        cyg_drv_cond_wait( &ctlr->queue );

    if (info->connected && chan->valid)
    {
        ctlr->busy = true;
        
        if (NULL != chan->partition)
        {
            pos += chan->partition->start;
            last = chan->partition->end;
        }
        else
        {
            last = info->blocks_num-1;
        }
    
        D(("disk write block=%d len=%d buf=%p\n", pos, *len, buf));

        while( size > 0 )
        {
            cyg_uint32 tfr = size;
        
            if (pos > last)
            {
                res = -EIO;
                goto done;
            }

            if( tfr > info->ident.max_transfer )
                tfr = info->ident.max_transfer;

            ctlr->result = -EWOULDBLOCK;

            cyg_drv_dsr_lock();
            
            res = (funs->write)(chan, (void*)bbuf, tfr, pos);

            if( res == -EWOULDBLOCK )
            {
                // If the driver replys EWOULDBLOCK, then the transfer is
                // being handled asynchronously and when it is finished it
                // will call disk_transfer_done(). This will wake us up here
                // to continue.

                while( ctlr->result == -EWOULDBLOCK )
                    cyg_drv_cond_wait( &ctlr->async );

                res = ctlr->result;
            }

            cyg_drv_dsr_unlock();
            
            if (ENOERR != res)
                goto done;
 
            if (!info->connected)
            {
                res = -EINVAL;
                goto done;
            }

            bbuf        += tfr * info->block_size;
            pos         += tfr;
            size        -= tfr;
            
        }
 
        ctlr->busy = false;
        cyg_drv_cond_signal( &ctlr->queue );
    }
    else
        res = -EINVAL;

done:
    
    cyg_drv_mutex_unlock( &ctlr->lock );
#ifdef CYGPKG_KERNEL    
    cyg_thread_yield();
#endif
    
    *len -= size;
    return res;
}

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

static void disk_transfer_done(struct disk_channel *chan, Cyg_ErrNo res)
{
    disk_controller    *ctlr = chan->controller;    

    ctlr->result = res;
    
    cyg_drv_cond_signal( &ctlr->async );
}

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

static cyg_bool
disk_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
{
    cyg_devtab_entry_t *t     = (cyg_devtab_entry_t *) handle;
    disk_channel       *chan  = (disk_channel *) t->priv;
    cyg_disk_info_t    *cinfo = chan->info;
 
    if (!cinfo->connected || !chan->valid)
        return false;
    else
        return true;
}

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

static Cyg_ErrNo 
disk_get_config(cyg_io_handle_t  handle, 
                cyg_uint32       key, 
                void            *xbuf,
                cyg_uint32      *len)
{
    cyg_devtab_entry_t *t    = (cyg_devtab_entry_t *) handle;
    disk_channel       *chan = (disk_channel *) t->priv;
    disk_controller    *ctlr = chan->controller;    
    cyg_disk_info_t    *info = chan->info;
    cyg_disk_info_t    *buf  = (cyg_disk_info_t *) xbuf;
    disk_funs          *funs = chan->funs;
    Cyg_ErrNo res = ENOERR;
 
    cyg_drv_mutex_lock( &ctlr->lock );

    while( ctlr->busy )
        cyg_drv_cond_wait( &ctlr->queue );

    if (info->connected && chan->valid)
    {
        ctlr->busy = true;
    
        D(("disk get config key=%d\n", key)); 
    
        switch (key) {
        case CYG_IO_GET_CONFIG_DISK_INFO:
            if (*len < sizeof(cyg_disk_info_t)) {
                res = -EINVAL;
                break;
            }
            D(("chan->info->block_size %u\n", chan->info->block_size ));
            D(("chan->info->blocks_num %u\n", chan->info->blocks_num ));
            D(("chan->info->phys_block_size %u\n", chan->info->phys_block_size ));
            *buf = *chan->info;
            *len = sizeof(cyg_disk_info_t);
            break;       

        default:
            // pass down to lower layers
            res = (funs->get_config)(chan, key, xbuf, len);
        }
        
        ctlr->busy = false;
        cyg_drv_cond_signal( &ctlr->queue );
    }
    else
        res = -EINVAL;

    cyg_drv_mutex_unlock( &ctlr->lock );    
    
    return res;
}

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

static Cyg_ErrNo 
disk_set_config(cyg_io_handle_t  handle, 
                cyg_uint32       key, 
                const void      *xbuf, 
                cyg_uint32      *len)
{
    cyg_devtab_entry_t *t    = (cyg_devtab_entry_t *) handle;
    disk_channel       *chan = (disk_channel *) t->priv;
    disk_controller    *ctlr = chan->controller;    
    cyg_disk_info_t    *info = chan->info;
    disk_funs          *funs = chan->funs;
    Cyg_ErrNo res = ENOERR;
    
    cyg_drv_mutex_lock( &ctlr->lock );

    while( ctlr->busy )
        cyg_drv_cond_wait( &ctlr->queue );

    if (info->connected && chan->valid)
    {
        ctlr->busy = true;
        
        D(("disk set config key=%d\n", key)); 

        switch ( key )
        {
        case CYG_IO_SET_CONFIG_DISK_MOUNT:
            chan->mounts++;
            info->mounts++;
            D(("disk mount: chan %d disk %d\n",chan->mounts, info->mounts));
            break;
            
        case CYG_IO_SET_CONFIG_DISK_UMOUNT:
            chan->mounts--;
            info->mounts--;
            D(("disk umount: chan %d disk %d\n",chan->mounts, info->mounts));            
            break;
            
        default:
            break;
        }
        
        // pass down to lower layers
        res = (funs->set_config)(chan, key, xbuf, len);
        
        ctlr->busy = false;
        cyg_drv_cond_signal( &ctlr->queue );
    }
    else
        res = -EINVAL;
    
    cyg_drv_mutex_unlock( &ctlr->lock );

    return res;
    
}

// ---------------------------------------------------------------------------
// EOF disk.c

⌨️ 快捷键说明

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