微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM的嵌入式Linux移植体验之设备驱动

ARM的嵌入式Linux移植体验之设备驱动

时间:11-13 来源:互联网 点击:

static int erase_write (struct mtd_info *mtd, unsigned long pos,
int len, const char *buf)
{
 struct erase_info erase;
 DECLARE_WAITQUEUE(wait, current);
 wait_queue_head_t wait_q;
 size_t retlen;
 int ret;

 /*
 * First, let's erase the flash block.
 */

 init_waitqueue_head(wait_q);
 erase.mtd = mtd;
 erase.callback = erase_callback;
 erase.addr = pos;
 erase.len = len;
 erase.priv = (u_long)wait_q;

 set_current_state(TASK_INTERRUPTIBLE);
 add_wait_queue(wait_q, wait);

 ret = MTD_ERASE(mtd, erase);
 if (ret) {
  set_current_state(TASK_RUNNING);
  remove_wait_queue(wait_q, wait);
  printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] " "on /"%s/" failed/n",
pos, len, mtd->name);
  return ret;
 }

 schedule(); /* Wait for erase to finish. */
 remove_wait_queue(wait_q, wait);

 /*
 * Next, writhe data to flash.
 */

 ret = MTD_WRITE (mtd, pos, len, retlen, buf);
 if (ret)
  return ret;
 if (retlen != len)
  return -EIO;
 return 0;
}

static int write_cached_data (struct mtdblk_dev *mtdblk)
{
 struct mtd_info *mtd = mtdblk->mtd;
 int ret;

 if (mtdblk->cache_state != STATE_DIRTY)
  return 0;

 DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for /"%s/" "
"at 0x%lx, size 0x%x/n", mtd->name,
mtdblk->cache_offset, mtdblk->cache_size);

 ret = erase_write (mtd, mtdblk->cache_offset,
mtdblk->cache_size, mtdblk->cache_data);
 if (ret)
  return ret;

 mtdblk->cache_state = STATE_EMPTY;
 return 0;
}

static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
int len, const char *buf)
{
 …
}

static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
int len, char *buf)
{
 …
}

static int mtdblock_open(struct inode *inode, struct file *file)
{
 …
}

static release_t mtdblock_release(struct inode *inode, struct file *file)
{
 int dev;
 struct mtdblk_dev *mtdblk;
 DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release/n");

 if (inode == NULL)
  release_return(-ENODEV);

 dev = minor(inode->i_rdev);
 mtdblk = mtdblks[dev];

 down(mtdblk->cache_sem);
 write_cached_data(mtdblk);
 up(mtdblk->cache_sem);

 spin_lock(mtdblks_lock);
 if (!--mtdblk->count) {
  /* It was the last usage. Free the device */
  mtdblks[dev] = NULL;
  spin_unlock(mtdblks_lock);
  if (mtdblk->mtd->sync)
   mtdblk->mtd->sync(mtdblk->mtd);
   put_mtd_device(mtdblk->mtd);
   vfree(mtdblk->cache_data);
   kfree(mtdblk);
 } else {
  spin_unlock(mtdblks_lock);
 }

 DEBUG(MTD_DEBUG_LEVEL1, "ok/n");
 
 BLK_DEC_USE_COUNT;
 release_return(0);
}

/*
* This is a special request_fn because it is executed in a process context
* to be able to sleep independently of the caller. The
* io_request_lock (for 2.5) or queue_lock (for >=2.5) is held upon entry
* and exit. The head of our request queue is considered active so there is
* no need to dequeue requests before we are done.
*/
static void handle_mtdblock_request(void)
{
 struct request *req;
 struct mtdblk_dev *mtdblk;
 unsigned int res;

 for (;;) {
  INIT_REQUEST;
  req = CURRENT;
  spin_unlock_irq(QUEUE_LOCK(QUEUE));
  mtdblk = mtdblks[minor(req->rq_dev)];
  res = 0;

  if (minor(req->rq_dev) >= MAX_MTD_DEVICES)
   panic("%s : minor out of bound", __FUNCTION__);

  if (!IS_REQ_CMD(req))
   goto end_req;

  if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
   goto end_req;

  // Handle the request
  switch (rq_data_dir(req))
  {
   int err;

   case READ:
    down(mtdblk->cache_sem);
    err = do_cached_read (mtdblk, req->sector 9,
req->current_nr_sectors 9,
req->buffer);
    up(mtdblk->cache_sem);
    if (!err)
     res = 1;
    break;

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top