#include "tusb_option.h"
#if defined(STM32F102x6) || defined(STM32F102xB) || \
defined(STM32F103x6) || defined(STM32F103xB) || \
defined(STM32F103xE) || defined(STM32F103xG)
#define STM32F1_FSDEV
#endif
#if TUSB_OPT_DEVICE_ENABLED && \
( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4) || \
(TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \
)
#undef USE_HAL_DRIVER
#include "device/dcd.h"
#include "portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h"
#ifndef MAX_EP_COUNT
# define MAX_EP_COUNT 8U
#endif
#ifndef DCD_STM32_BTABLE_BASE
# define DCD_STM32_BTABLE_BASE 0U
#endif
#ifndef DCD_STM32_BTABLE_LENGTH
# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE)
#endif
#ifndef USE_SOF
# define USE_SOF 0
#endif
TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware");
TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH),
"BTABLE does not fit in PMA RAM");
TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes");
typedef struct
{
uint8_t * buffer;
uint16_t total_len;
uint16_t queued_len;
uint16_t pma_ptr;
uint8_t max_packet_size;
uint8_t pma_alloc_size;
} xfer_ctl_t;
static xfer_ctl_t xfer_status[MAX_EP_COUNT][2];
static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir)
{
return &xfer_status[epnum][dir];
}
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
static uint8_t remoteWakeCountdown;
static void dcd_handle_bus_reset(void);
static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix);
static void dcd_ep_ctr_handler(void);
static uint8_t open_ep_count;
static uint16_t ep_buf_ptr; static void dcd_pma_alloc_reset(void);
static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length);
static void dcd_pma_free(uint8_t ep_addr);
static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes);
static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes);
static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) {
*reg = (uint16_t)(*reg & ~mask);
}
static inline void clear_istr_bits(uint16_t mask) {
USB->ISTR = ~mask;
}
void dcd_init (uint8_t rhport)
{
for(uint32_t i = 0; i<200; i++) {
asm("NOP");
}
USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
for(uint32_t i = 0; i<200; i++) {
asm("NOP");
}
reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN); for(uint32_t i = 0; i<200; i++) {
asm("NOP");
}
USB->CNTR = 0;
USB->BTABLE = DCD_STM32_BTABLE_BASE;
USB->ISTR = 0;
for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
{
pcd_set_endpoint(USB,i,0u);
}
USB->CNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
dcd_handle_bus_reset();
if ( dcd_connect ) dcd_connect(rhport);
}
#if defined(USB_BCDR_DPPU)
void dcd_disconnect(uint8_t rhport)
{
(void) rhport;
USB->BCDR &= ~(USB_BCDR_DPPU);
}
void dcd_connect(uint8_t rhport)
{
(void) rhport;
USB->BCDR |= USB_BCDR_DPPU;
}
#elif defined(SYSCFG_PMC_USB_PU)
void dcd_disconnect(uint8_t rhport)
{
(void) rhport;
SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
}
void dcd_connect(uint8_t rhport)
{
(void) rhport;
SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
}
#endif
void dcd_int_enable (uint8_t rhport)
{
(void)rhport;
__DSB();
__ISB();
#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0
NVIC_EnableIRQ(USB_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
NVIC_EnableIRQ(USB_LP_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
#ifdef SYSCFG_CFGR1_USB_IT_RMP
if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
{
NVIC_EnableIRQ(USB_HP_IRQn);
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
}
else
#endif
{
NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
}
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
NVIC_EnableIRQ(USB_HP_IRQn);
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
#else
#error Unknown arch in USB driver
#endif
}
void dcd_int_disable(uint8_t rhport)
{
(void)rhport;
#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0
NVIC_DisableIRQ(USB_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
NVIC_DisableIRQ(USB_LP_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
#ifdef SYSCFG_CFGR1_USB_IT_RMP
if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
{
NVIC_DisableIRQ(USB_HP_IRQn);
NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
}
else
#endif
{
NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn);
NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn);
}
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
NVIC_DisableIRQ(USB_HP_IRQn);
NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn);
#else
#error Unknown arch in USB driver
#endif
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
(void) rhport;
(void) dev_addr;
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
}
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
USB->CNTR |= (uint16_t) USB_CNTR_RESUME;
remoteWakeCountdown = 4u; }
static const tusb_desc_endpoint_t ep0OUT_desc =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = 0x00,
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
.wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
.bInterval = 0
};
static const tusb_desc_endpoint_t ep0IN_desc =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = 0x80,
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
.wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
.bInterval = 0
};
static void dcd_handle_bus_reset(void)
{
USB->DADDR = 0u;
for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
{
pcd_set_endpoint(USB,i,0u);
}
dcd_pma_alloc_reset();
dcd_edpt_open (0, &ep0OUT_desc);
dcd_edpt_open (0, &ep0IN_desc);
USB->DADDR = USB_DADDR_EF; }
static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
{
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
if((wEPRegVal & USB_EP_CTR_TX) == 0U)
{
return;
}
pcd_clear_tx_ep_ctr(USB, EPindex);
xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN);
if((xfer->total_len != xfer->queued_len))
{
dcd_transmit_packet(xfer, EPindex);
}
else
{
dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
{
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex);
xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT);
if((wEPRegVal & USB_EP_CTR_RX) == 0U)
{
return;
}
if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U))
{
uint8_t userMemBuf[8];
if(count == 8) {
pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK);
pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK);
dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8);
dcd_event_setup_received(0, (uint8_t*)userMemBuf, true);
}
}
else
{
if(EPindex != 0u)
{
pcd_clear_rx_ep_ctr(USB, EPindex);
}
if (count != 0U)
{
#if 0#endif
{
dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
{
dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true);
}
else
{
uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len;
if(remaining >= xfer->max_packet_size) {
pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size);
} else {
pcd_set_ep_rx_cnt(USB, EPindex,remaining);
}
pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
}
}
if(EPindex == 0u)
{
pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex);
}
}
static void dcd_ep_ctr_handler(void)
{
uint32_t wIstr;
while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
{
if ((wIstr & USB_ISTR_DIR) == 0U)
{
dcd_ep_ctr_tx_handler(wIstr);
}
else
{
dcd_ep_ctr_rx_handler(wIstr);
}
}
}
void dcd_int_handler(uint8_t rhport) {
(void) rhport;
uint32_t int_status = USB->ISTR;
if(int_status & USB_ISTR_RESET) {
clear_istr_bits(USB_ISTR_RESET);
dcd_handle_bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
return; }
if (int_status & USB_ISTR_CTR)
{
dcd_ep_ctr_handler();
}
if (int_status & USB_ISTR_WKUP)
{
reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE);
reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP);
clear_istr_bits(USB_ISTR_WKUP);
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
if (int_status & USB_ISTR_SUSP)
{
USB->CNTR |= USB_CNTR_FSUSP;
USB->CNTR |= USB_CNTR_LPMODE;
clear_istr_bits(USB_ISTR_SUSP);
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
#if USE_SOF
if(int_status & USB_ISTR_SOF) {
clear_istr_bits(USB_ISTR_SOF);
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
#endif
if(int_status & USB_ISTR_ESOF) {
if(remoteWakeCountdown == 1u)
{
USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME);
}
if(remoteWakeCountdown > 0u)
{
remoteWakeCountdown--;
}
clear_istr_bits(USB_ISTR_ESOF);
}
}
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
request->bRequest == TUSB_REQ_SET_ADDRESS )
{
uint8_t const dev_addr = (uint8_t) request->wValue;
reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); }
}
static void dcd_pma_alloc_reset(void)
{
ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; for(uint32_t i=0; i<MAX_EP_COUNT; i++)
{
xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U;
xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U;
xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U;
xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U;
}
}
static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir);
if(epXferCtl->pma_alloc_size != 0U)
{
TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); return epXferCtl->pma_ptr;
}
uint16_t addr = ep_buf_ptr;
ep_buf_ptr = (uint16_t)(ep_buf_ptr + length);
TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF);
epXferCtl->pma_ptr = addr;
epXferCtl->pma_alloc_size = length;
return addr;
}
static void dcd_pma_free(uint8_t ep_addr)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
TU_ASSERT(open_ep_count > 2, );
TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, );
open_ep_count--;
if(open_ep_count == 2)
{
ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE;
for(uint32_t i=1; i<MAX_EP_COUNT; i++)
{
xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U;
xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U;
xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U;
xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U;
}
}
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
(void)rhport;
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
const uint16_t epMaxPktSize = tu_edpt_packet_size(p_endpoint_desc);
uint16_t pma_addr;
uint32_t wType;
TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
TU_ASSERT(epnum < MAX_EP_COUNT);
switch(p_endpoint_desc->bmAttributes.xfer) {
case TUSB_XFER_CONTROL:
wType = USB_EP_CONTROL;
break;
#if (0)
case TUSB_XFER_ISOCHRONOUS: wType = USB_EP_ISOCHRONOUS;
break;
#endif
case TUSB_XFER_BULK:
wType = USB_EP_CONTROL;
break;
case TUSB_XFER_INTERRUPT:
wType = USB_EP_INTERRUPT;
break;
default:
TU_ASSERT(false);
}
pcd_set_eptype(USB, epnum, wType);
pcd_set_ep_address(USB, epnum, epnum);
pcd_clear_ep_kind(USB,0);
pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, epMaxPktSize);
if(dir == TUSB_DIR_IN)
{
*pcd_ep_tx_address_ptr(USB, epnum) = pma_addr;
pcd_set_ep_tx_cnt(USB, epnum, epMaxPktSize);
pcd_clear_tx_dtog(USB, epnum);
pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK);
}
else
{
*pcd_ep_rx_address_ptr(USB, epnum) = pma_addr;
pcd_set_ep_rx_cnt(USB, epnum, epMaxPktSize);
pcd_clear_rx_dtog(USB, epnum);
pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK);
}
xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize;
return true;
}
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
}
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
uint32_t const epnum = tu_edpt_number(ep_addr);
uint32_t const dir = tu_edpt_dir(ep_addr);
if(dir == TUSB_DIR_IN)
{
pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS);
}
else
{
pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS);
}
dcd_pma_free(ep_addr);
}
static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix)
{
uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
if(len > xfer->max_packet_size) {
len = xfer->max_packet_size;
}
uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix);
#if 0#endif
{
dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + len);
pcd_set_ep_tx_cnt(USB,ep_ix,len);
pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID);
}
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir);
xfer->buffer = buffer;
xfer->total_len = total_bytes;
xfer->queued_len = 0;
if ( dir == TUSB_DIR_OUT )
{
if (epnum == 0 && buffer == NULL)
{
xfer->buffer = (uint8_t*)_setup_packet;
}
if(total_bytes > xfer->max_packet_size)
{
pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size);
} else {
pcd_set_ep_rx_cnt(USB,epnum,total_bytes);
}
pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID);
}
else {
dcd_transmit_packet(xfer,epnum);
}
return true;
}
#if 0#endif
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
if (ep_addr & 0x80)
{ pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL);
}
else
{ pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL);
}
}
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
if (ep_addr & 0x80)
{ ep_addr &= 0x7F;
pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK);
pcd_clear_tx_dtog(USB,ep_addr);
}
else
{
pcd_clear_rx_dtog(USB,ep_addr);
pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK);
}
}
static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes)
{
uint32_t n = ((uint32_t)wNBytes + 1U) >> 1U;
uint32_t i;
uint16_t temp1, temp2;
const uint8_t * srcVal;
__IO uint16_t *pdwVal;
srcVal = src;
pdwVal = &pma[PMA_STRIDE*(dst>>1)];
for (i = n; i != 0; i--)
{
temp1 = (uint16_t) *srcVal;
srcVal++;
temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ;
*pdwVal = temp2;
pdwVal += PMA_STRIDE;
srcVal++;
}
return true;
}
#if 0#endif
static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes)
{
uint32_t n = (uint32_t)wNBytes >> 1U;
uint32_t i;
__IO const uint16_t *pdwVal;
uint32_t temp;
pdwVal = &pma[PMA_STRIDE*(src>>1)];
uint8_t *dstVal = (uint8_t*)dst;
for (i = n; i != 0U; i--)
{
temp = *pdwVal;
pdwVal += PMA_STRIDE;
*dstVal++ = ((temp >> 0) & 0xFF);
*dstVal++ = ((temp >> 8) & 0xFF);
}
if (wNBytes % 2)
{
temp = *pdwVal;
pdwVal += PMA_STRIDE;
*dstVal++ = ((temp >> 0) & 0xFF);
}
return true;
}
#if 0#endif
#endif