📄 mscbot.c
字号:
// what direction is the data supposed to flow?
g_bot_xfer_dir = g_bot_cbw.bCBWFlags & kbm_cbw_dir_d2h ? k_dir_read : k_dir_write;
// reverse pipe for reads
if (g_bot_xfer_dir == k_dir_read)
{
if (_tx_missed_ack)
ndp2_tx_enable_ex();
else
{
_endpoint_tx_enable(k_tx_pipe);
}
}
// convert the logical lun (from the cbw) into a physical lun (index into lun tables)
_active_lun = _lun_log2phy(g_bot_cbw.bCBWlun);
#ifdef k_pfm_demo
// there are 5 phy luns, but only 4 leds. assumes sd and mmc "share" an led.
_mcu_register_clr_bits(x_gpiob_out, 0x10 << _min(3, _active_lun));
#endif
// the mux is no longer enabled here because this is an isr.
// the mux is enabled in the dev thread when it wakes on sync-cbw.
// _lun_enable_mux(_active_lun)();
// data access led on during read/write
switch (g_bot_cbw.cdb[0])
{
case k_protocol_read_10:
case k_protocol_read_12:
case k_protocol_write_10:
case k_protocol_write_12:
case k_protocol_verify_10:
if (g_post_access_blink_secs) //Are we blinking still?
{
irq_control(k_irq_cpu_t1, kbm_irqctl_mask); //then stop the timer
g_post_access_blink_secs = 0x00;
trace0(0, dev, 0, "next data access blinker off");
}
if (g_blink_interval) //Are we supposed to blink?
{
irq_control(k_irq_cpu_t1, kbm_irqctl_unmask); //then start the timer
_data_access = k_true;
}
//rcc code to turn OFF leds during access to respective luns LEDs are ON when card inserted
// they go off when card is out or blink off when accessed.
#ifdef k_pfm_led
// there are 5 phy luns, but only 4 leds. assumes sd and mmc "share" an led.
//_mcu_register_clr_bits(x_gpiob_out, 0x10 << _min(3, _active_lun));
if (_lun_is_media_present(_active_lun))
{
switch (_active_lun)
{
case k_lun_cf:
trace0(0, dev, 66, "CF LED OFF!");
_mcu_register_clr_bits(x_gpiob_out, kbm_gpio13);
break;
case k_lun_ms:
trace0(0, dev, 66, "MS LED OFF!");
_mcu_register_clr_bits(x_gpiob_out, kbm_gpio12);
break;
case k_lun_sm:
trace0(0, dev, 66, "SM LED OFF!");
_mcu_register_clr_bits(x_gpiob_out, kbm_gpio14);
break;
case k_lun_sd:
trace0(0, dev, 66, "SD LED OFF!");
_mcu_register_clr_bits(x_gpiob_out, kbm_gpio15);
break;
case k_lun_mmc:
trace0(0, dev, 66, "MMC LED OFF!");
_mcu_register_clr_bits(x_gpiob_out, kbm_gpio15);
break;
}
}
#endif
break;
}
// break the interrupt chain until the foreground is done and restarts the chain
_hpbot_thread_entry = NULL;
// tell the fgnd to run the command
//thread_set_sync(g_ix_dev_thread, kbm_sync_cbw);
g_thread[g_ix_dev_thread].bits_got |= kbm_sync_cbw;
//_profile_off(5);
return (k_success);
// usbrst
case k_irq_usb_stat_reset:
case k_irq_usb_reset:
_thread_clr_sync(kbm_sync_all);
hpbot_wait_create();
// let the default interrupt handler see this also
return (k_ignored);
// let the default inrt handler handle everything else
default:
trace0(0, bot, 0, "intr ignored");
return (k_ignored);
}
}
//------------------------------------------------------------------------------
// this is only called from the foreground.
// it is called immediately after processing a msc command.
// it allows the fgnd to restart the high priority thread's
// interrupt chain after the data phase of a transfer
//------------------------------------------------------------------------------
void fgnd_hpbot_wait_status_start(uint8 rslt) reentrant
{
// wait to hear the innak before sending the status
trace1(0, bot, 0, "fgnd_hpbot_wait_status_start(%d)", rslt);
_mcu_begin_critical_section();
_endpoint_unmask_innak(k_rx_pipe);
_endpoint_unmask_outnak(k_rx_pipe);
_hpbot_thread_entry = hpbot_wait_status_start;
_status = rslt;
_mcu_end_critical_section();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static t_result hpbot_wait_status_start(uint8 intr) reentrant using 1
{
trace1(0, bot, 0, "hpbot_wait_status_start(%d)", intr);
switch (intr)
{
// innak
case k_irq_nak2tx:
trace0(0, bot, 99, "innak");
// the status stage cannot start on a read until the final data packet has been transmitted
// to the host, and ack'd. this can be detected by checking to see that both ramrd a and b
// are set (ie, not in use, and/or waiting to be transmitted). this helps avoids mistaking
// an innak for the data as the innak for the status. in theory the status stage shouldn't
// even be run intil after all the data has been sent and ack'd by the host. but, since we
// are going for minimum csw turnaround time, we want to send the status asap. the tricky
// thing here is knowing that the data stage has ended. this code may not be perfected
// handle all error conditions yet... caveat implementor...
if (g_bot_xfer_dir == k_dir_read)
if ((_mcu_register_rd(x_isr0) & (kbm_isr0_ramrd_a |kbm_isr0_ramrd_b)) != (kbm_isr0_ramrd_a |kbm_isr0_ramrd_b))
{
// a transmittable buffer is still in play... not time to send the csw yet...
_endpoint_unmask_innak(k_tx_pipe);
return (k_ignored);
}
// it is not safe to turn off autoxfer until after innak is heard.
// otherwise you could lose possible retransmit of the final data packet.
// it does not hurt to turn it off if it was already off though...
trace0(0, bot, 0, "AUTOXFER ==> OFF");
_mcu_register_clr_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans);
_stall_ndp2_rx = k_no;
return (hpbot_send_status(_status));
// outnak
case k_irq_nak2rx:
trace0(0, bot, 99, "outnak");
// it is not safe to turn off autoxfer until after innak is heard.
// otherwise you could lose possible retransmit of the final data packet.
// it does not hurt to turn it off if it was already off though...
trace0(0, bot, 0, "AUTOXFER ==> OFF");
_mcu_register_clr_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans);
_stall_ndp2_rx = k_yes;
return (hpbot_send_status(_status));
// usbrst
case k_irq_usb_stat_reset:
case k_irq_usb_reset:
_thread_clr_sync(kbm_sync_all);
hpbot_wait_create();
// let the default interrupt handler see this also
return (k_ignored);
// let the default intr handler handle everything else
default:
trace0(0, bot, 0, "intr ignored");
return (k_ignored);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static uint8 _nakkount = 0;
static t_result hpbot_wait_status_end(uint8 intr) reentrant using 1
{
trace1(0, bot, 0, "hpbot_wait_status_end(%d)", intr);
if (_data_access) // Is this a data access cmd?
{
if (g_blink_interval) //Were we blinking?
{
//do we need to continue blinking?
//we could do a direct read from nvstore but I believe that is a waste of time on this fast code
g_post_access_blink_secs = g_nvstore_post_access_blink_secs;
if (!g_post_access_blink_secs) //No need to blink
{
irq_control(k_irq_cpu_t1, kbm_irqctl_mask); //then stop the timer
}
else
{
trace0(0, dev, 0, "blinker on");
}
}
_data_access = k_false;
}
dev_turn_off_activity_indicator();
#ifdef k_pfm_led
if (_lun_is_media_present(_active_lun))
{
switch (_active_lun)
{
case k_lun_cf:
trace0(0, dev, 66, "CF LED ON!");
_mcu_register_set_bits(x_gpiob_out, kbm_gpio13);
break;
case k_lun_ms:
trace0(0, dev, 66, "MS LED ON!");
_mcu_register_set_bits(x_gpiob_out, kbm_gpio12);
break;
case k_lun_sm:
trace0(0, dev, 66, "SM LED ON!");
_mcu_register_set_bits(x_gpiob_out, kbm_gpio14);
break;
case k_lun_sd:
if (_lun_is_media_known(_active_lun))
{
trace0(0, dev, 66, "SD LED ON!");
_mcu_register_set_bits(x_gpiob_out, kbm_gpio15);
}
break;
case k_lun_mmc:
if (_lun_is_media_known(_active_lun))
{
trace0(0, dev, 66, "MMC LED ON!");
_mcu_register_set_bits(x_gpiob_out, kbm_gpio15);
}
break;
}
}
#endif
switch (intr)
{
// usbtx:
case k_irq_ramrd_a:
trace0(0, bot, 10, "got the kbm_sync_usbtx");
_nakkount = 0;
_endpoint_rx_enable(k_rx_pipe);
_buffer_rx_enable(4);
_hpbot_thread_entry = hpbot_wait_cbw;
return (k_success);
// outnak
case k_irq_nak2rx:
if (_nakkount++ < 200)
{
trace0(0, bot, 11, "alert - got the kbm_sync_outnak - *before* the tx - dropped ack?");
_endpoint_unmask_outnak(k_rx_pipe);
return (k_success);
}
// detecting outnak before tx means dropped ack, unless pipe is stalled.
_nakkount = 0;
trace0(0, bot, 11, "got the kbm_sync_outnak - dropped ack?");
if (_ndp2_rx_stalled)
{
_ndp2_rx_stalled = k_no;
trace0(0, bot, 12, "...while stall in progress...");
return (k_success);
}
_tx_missed_ack = k_yes;
trace0(0, bot, 11, "dropped ack");
_endpoint_unmask_outnak(k_rx_pipe);
_hpbot_thread_entry = hpbot_wait_pipe_ready_for_rx;
return (k_success);
// usbrst
case k_irq_usb_stat_reset:
case k_irq_usb_reset:
//case k_irq_timer1: - this case is kind of a hold over from the first seat 'o the pants
// debug session in the pre-comdex'00 days. if the outnaks don't start coming (the only
// reason for a timeout to occur) then the device is dead. the host ain't pinging.
// so you are eventually gonna either get a usbreset, or the host will drop you like
// a cold turd. in either case, you have already lost.
_thread_clr_sync(kbm_sync_all);
hpbot_wait_create();
// let the default interrupt handler see this also
return (k_ignored);
// let the default inrt handler handle everything else
default:
trace0(0, bot, 0, "intr ignored");
return (k_ignored);
}
}
// length must be less than 64 bytes, and must contain the
// entire data portion of the transfer. this code takes up
// a lot of instructions and is used for sending small bot
// data payloads for non-media data commands like mode sense
// inquiry, etc.
void mscbot_tx_data_buffer(uint8* buffer, uint8 length) reentrant
{
uint8 pnr;
trace1(0, bot, 0, "mscbot_tx_data_buffer() - quick sending a %d byte data response", length) ;
pnr = mmu_allocate();
_thread_clr_sync(kbm_sync_usbtx);
length = _min( (uint32) length, _mscbot_residue_32()); // alloc length
mmu_wr_pkt(k_tx_pipe, pnr, buffer, length);
txfifo_wr(k_tx_pipe, pnr);
_mscbot_decr_residue(length);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// length must be less than 64 bytes, and must contain the
// entire data portion of the transfer. this code takes up
// a lot of instructions and is used for receiving small bot
// data payloads for non-media data commands like mode sense
// inquiry, etc.
//WARNING!! This fn assumes that this packet arrives at buffer B. This will work because we
//receive our cbw only on buffer A
uint8 mscbot_rx_data_buffer(uint8* buffer, uint8 length) reentrant
{
trace1(0, bot, 0, "mscbot_rx_data_buffer() - quick receiving a %d byte data", length) ;
thread_clr_sync(kbm_sync_usbrx);
_endpoint_rx_enable(k_rx_pipe);
_buffer_rx_enable(5);
thread_set_timer(200);
while (!thread_got_sync(kbm_sync_usbrx))
{
if (thread_got_sync(kbm_sync_timer))
{
return (k_timeout);
}
}
thread_clr_sync(kbm_sync_usbrx);
mmu_rd_pkt(5, length, buffer);
return (k_success);
}
//---eof------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -