📄 disk.c
字号:
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 + -