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

📄 fmc.c

📁 <B>SMSC USB2.0 Flash硬盘驱动源码</B>
💻 C
📖 第 1 页 / 共 3 页
字号:
//   g_n_lb_this_xfer     - specifies the total number of logical blocks to move
//                          for this transfer per the protocol
//   _lun_data(lun, max_lb_per_split) - specifies the maximum number of logical blocks that the
//                          drive can handle in a single command
//   _lun_data(lun, max_lb_per_burst) - specifies the maximum number of logical blocks that the
//                          drive can deliver before generating an interrupt
//   g_fmc_begin_xfer_callback - specifies the callback function to begin a xfer
//   g_fmc_end_xfer_callback - specifies the callback function to end a xfer
//   g_fmc_begin_split_callback - specifies the callback function to begin a split;
//                                i.e., issue the command
//   g_fmc_end_split_callback - specifies the callback function to end a split;
//                              i.e., check for error
//   g_fmc_begin_burst_callback - specifies the callback function to begin a burst;
//                                i.e., check drive ready
//   g_fmc_end_burst_callback - specifies the callback function to end a burst;
//                              i.e., check for error
//
//   This is a FUNCTION, not a DFA.
//
// Since:
//   fmc-1.0
//------------------------------------------------------------------------------
// oddly enough, moving these to xdata a tiny smidge is faster
// than manipulating them on the stack...
xdata t_udw32 n_lb_this_burst;
xdata t_udw32 n_bytes_this_burst;
xdata uint32 tmp;
t_result fmc_transfer() reentrant
{
  // profile:
  //   ms reads:  76msec avg to 230msec max per 64Kbytes
  //   ms writes: 145msec to 150msec per 64Kbytes

  //if ((g_bot_xfer_dir == k_dir_read)&&
  //    (g_bot_data_len.u32 > 0xE000)){_profile_on(7);}
  TRACE0(29, fmc, 1, "fmc_transfer()");

  // do this to get kbm_sync_abort delivered if there is traffic on the control pipe
  _isr_bind_dma_owner(g_tid, kbm_sync_none);

  // begin the xfer
  //_profile_on(4);
  g_fmc_rslt = (*g_fmc_begin_xfer_callback)();
  //_profile_off(4);
  if (k_success != g_fmc_rslt)
    goto EXIT;

  // need to disable auto transfer?
  if (!(g_fmc_options & kbm_fmc_disable_auto_xfer))
  {
    // enable auto transfer - start receiving data packets
    _mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans);
    TRACE0(30, fmc, 0, "auto-transfer bit on");
  }

  //------------------------------------------------------------------------------
  // moved from inside the burst loop to improve speed of MS transfers
  //------------------------------------------------------------------------------
  // enable the block transfer hardware
  if (sie_is_high_speed())
  {
    TRACE0(31, fmc, 0, "HS mode set-->kbm_fmc_ctl_512_byte_pkt");
    _mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_512_byte_pkt);
  }
  else
  {
    TRACE0(32, fmc, 0, "FS mode clr-->kbm_fmc_ctl_512_byte_pkt");
    _mcu_register_clr_bits(x_fmc_ctl, kbm_fmc_ctl_512_byte_pkt);
  }
  // check to see if we need to force the 512 byte xfer irrespective of the speed
  if ((g_fmc_options & kbm_fmc_xfer_512_byte_pkt))
  {
    TRACE0(33, fmc, 0, "option forced set-->kbm_fmc_ctl_512_byte_pkt");
    _mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_512_byte_pkt);
  }
  //------------------------------------------------------------------------------

  // process each split in the transaction
  //while (g_n_lb_this_xfer.u32)
  while (!_u32_equ_0(g_n_lb_this_xfer))
  {
    _thread_clr_sync(kbm_sync_fmc_irq);

    // determine the number of logical blocks for this split
    tmp = _lun_data(max_lb_per_split);
    if (g_n_lb_this_xfer.u32 > tmp)
    {
      // split
      TRACE0(34, fmc, 0, "fmc_transfer() - multiple splits");
      g_n_lb_this_split.u32 = tmp;
    }
    else
    {
      // not split, or final split
      TRACE0(35, fmc, 0, "fmc_transfer() - single split");
      g_n_lb_this_split.u32 = g_n_lb_this_xfer.u32;
    }

    // begin the split
    TRACE2(36, fmc, 0, "n_lb_this_split: %04x%04x" , _hw(g_n_lb_this_split.u32), _lw(g_n_lb_this_split.u32));
    //_profile_on(5);
    g_fmc_rslt = (*g_fmc_begin_split_callback)();
    //_profile_off(5);
    if (k_success != g_fmc_rslt)
      goto EXIT;

    // process each burst in the split
    //while (g_n_lb_this_split.u32)
    while (!_u32_equ_0(g_n_lb_this_split))
    {
      // determine the number of logical blocks in this burst
      tmp = _lun_data(max_lb_per_burst);
      if (g_n_lb_this_split.u32 > tmp)
      {
        // multi-burst
        TRACE0(37, fmc, 0, "fmc_transfer() - multiple bursts");
        n_lb_this_burst.u32 = tmp;
      }
      else
      {
        // single burst, or final burst
        TRACE0(38, fmc, 0, "fmc_transfer() - single burst");
        n_lb_this_burst.u32 = g_n_lb_this_split.u32;
      }

      // determine the number of bytes in this burst
      TRACE2(39, fmc, 0, "n_lb_this_burst: %04x%04x", _hw(n_lb_this_burst.u32), _lw(n_lb_this_burst.u32));
      #if 1
      n_bytes_this_burst.u32 = n_lb_this_burst.u32 * 512L;
      #else
      // tried to hand multiply by a constant - didnt work right - needs work
      n_bytes_this_burst.u8.hi = n_lb_this_burst.u8.lh << 1;
      n_bytes_this_burst.u8.lh = n_lb_this_burst.u8.hl << 1;
      n_bytes_this_burst.u8.hl = n_lb_this_burst.u8.lo << 1;
      n_bytes_this_burst.u8.lo = 0;
      #endif

      // begin the burst
      //_profile_on(6);
      g_fmc_rslt = (*g_fmc_begin_burst_callback)();
      //_profile_off(6);
      if (k_success != g_fmc_rslt)
        goto EXIT;

      // clear, and unmask, the block xfer interrupt
      //irq_control(k_irq_blk_xfer_complete, kbm_irqctl_clear |kbm_irqctl_unmask);
      _mcu_register_wr(x_isr0, kbm_isr0_blk_xfer_complete);
      // AAA: do not take the interrupt at end of transfer and watch for a synchronizer.
      // instead poll for the bit and eliminate the isr entry/exit overhead.
      //_mcu_register_clr_bits(x_imr0, kbm_isr0_blk_xfer_complete);

      // write the count registers
      _mcu_register_wr(x_fmc_cnt3, n_bytes_this_burst.u8.hi);
      _mcu_register_wr(x_fmc_cnt2, n_bytes_this_burst.u8.lh);
      _mcu_register_wr(x_fmc_cnt1, n_bytes_this_burst.u8.hl);
      _mcu_register_wr(x_fmc_cnt0, n_bytes_this_burst.u8.lo);
      TRACE4(40, fmc, 0, "fmc_cnt#: %02x%02x%02x%02x", x_fmc_cnt3, x_fmc_cnt2, x_fmc_cnt1, x_fmc_cnt0);

      // prime the loop to "resume" transfer, w/o calling split/burst/xfer mechanisms
      // to allow luns to fix and/or correct errors in mid transfer, then to continue
      // data xfer.
      g_fmc_rslt = k_resume;
      while (g_fmc_rslt == k_resume)
      {
        _mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_blk_xfer_en);
        TRACE0(41, fmc, 0, "fmdu activated");

        // call a xfer-in-progress callback?
        //_profile_on(5);
        g_fmc_rslt = (*g_fmc_intra_burst_callback)();
        //_profile_off(5);
        if (k_success != g_fmc_rslt)
          goto EXIT;

        // !!! possible performance optimization is to make these fctns inline...
        // wait for the end of the burst
        if (g_fmc_options & kbm_fmc_end_burst_on_count_down)
        {
          // wait for the count to decrement to zero
          g_fmc_rslt = fmc_wait_count_down_with_timeout(g_fmc_timeout);
        }
        else
        {
          t_sync sync;
          // wait for the block transfer irq
          // unrolled: g_fmc_rslt = fmc_wait_blk_irq_with_timeout(g_fmc_timeout);
          // poll for bit instead of taking irq and waiting synch.
          //_profile_on(7);
          //trace0(0, fmc, 1, "fmc_wait_blk_irq_with_timeout()");
          thread_set_timer(g_fmc_timeout);
          do
          {
            sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer|kbm_sync_fmc_irq);
            _thread_clr_sync(sync);
            if (sync & kbm_sync_usbrst)
            {
              TRACE0(42, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: kbm_sync_usbrst");
              g_fmc_rslt = k_usbreset;
              break;
            }
            if (sync & kbm_sync_abort)
            {
              TRACE0(43, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: kbm_sync_abort");
              g_fmc_rslt = k_aborted;
              break;
            }
            if (sync & kbm_sync_timer)
            {
              TRACE0(44, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: timeout awaiting irq");
              g_fmc_rslt = k_timeout;
              break;
            }
            if (sync & kbm_sync_fmc_irq)
            {
              TRACE0(45, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: kbm_sync_fmc_irq") ;
              // set to success, since we don't know the cause of the error yet... the specific end-burst
              // function should determine the actual status fot eh fmc xfer
              g_fmc_rslt = k_success;
              break;
            }
          // AAA: added this to poll instead of taking the interrupt
          // cds: added isr bit fmc_irq to break out of loop for fmc error (ecc or otherwise) detection
          } while (!(_mcu_register_rd(x_isr0) & (kbm_isr0_blk_xfer_complete|kbm_isr0_fmc_irq) ));
          //_profile_off(7);
        }
        if (k_success != g_fmc_rslt)
        {
          goto EXIT;
        }

        // end the burst
        //_profile_on(6);
        g_fmc_rslt = (*g_fmc_end_burst_callback)();
        //_profile_off(6);
        if (k_resume == g_fmc_rslt)
        {
          TRACE0(46, fmc, 0, "resuming fmc transfer");
          continue;
        }
        else
          if (k_success != g_fmc_rslt)
          goto EXIT;
      }

      // update start block for next split
      g_start_lb_this_xfer.u32 += n_lb_this_burst.u32;
      // decrement the number of logical blocks remaining in the split
      g_n_lb_this_split.u32 -= n_lb_this_burst.u32;
      // decrement the number of logical blocks remaining in the transfer
      g_n_lb_this_xfer.u32 -= n_lb_this_burst.u32;
      // track the mscbot byte residue
      _mscbot_decr_residue(n_bytes_this_burst.u32);
    }

    // end the split
    //_profile_on(5);
    g_fmc_rslt = (*g_fmc_end_split_callback)();
    //_profile_off(5);
    if (k_success != g_fmc_rslt)
      goto EXIT;
  }

  EXIT:
  // check for an error
  if (k_success != g_fmc_rslt)
    fmc_abort_transfer();
  else
    _lun_data(sensep) = &sense_none;

  // end the xfer
  // ??? need to get the returned result?  can end_xfer fail the xfer?
  //_profile_on(4);
  (*g_fmc_end_xfer_callback)();
  //_profile_off(4);

  //_profile_off(7);
  // exit, stage left
  return g_fmc_rslt;
}

//---eof------------------------------------------------------------------------

⌨️ 快捷键说明

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