in regmap/regmap-spi-avmm.c [253:339]
static int br_pkt_phy_tx_prepare(struct spi_avmm_bridge *br)
{
char *tb, *tb_end, *pb, *pb_limit, *pb_eop = NULL;
unsigned int aligned_phy_len, move_size;
bool need_esc = false;
tb = br->trans_buf;
tb_end = tb + br->trans_len;
pb = br->phy_buf;
pb_limit = pb + ARRAY_SIZE(br->phy_buf);
*pb++ = PKT_SOP;
/*
* The driver doesn't support multiple channels so the channel number
* is always 0.
*/
*pb++ = PKT_CHANNEL;
*pb++ = 0x0;
for (; pb < pb_limit && tb < tb_end; pb++) {
if (need_esc) {
*pb = *tb++ ^ 0x20;
need_esc = false;
continue;
}
/* EOP should be inserted before the last valid char */
if (tb == tb_end - 1 && !pb_eop) {
*pb = PKT_EOP;
pb_eop = pb;
continue;
}
/*
* insert an ESCAPE char if the data value equals any special
* char.
*/
switch (*tb) {
case PKT_SOP:
case PKT_EOP:
case PKT_CHANNEL:
case PKT_ESC:
*pb = PKT_ESC;
need_esc = true;
break;
case PHY_IDLE:
case PHY_ESC:
*pb = PHY_ESC;
need_esc = true;
break;
default:
*pb = *tb++;
break;
}
}
/* The phy buffer is used out but transaction layer data remains */
if (tb < tb_end)
return -ENOMEM;
/* Store valid phy data length for spi transfer */
br->phy_len = pb - br->phy_buf;
if (br->word_len == 1)
return 0;
/* Do phy buf padding if word_len > 1 byte. */
aligned_phy_len = ALIGN(br->phy_len, br->word_len);
if (aligned_phy_len > sizeof(br->phy_buf))
return -ENOMEM;
if (aligned_phy_len == br->phy_len)
return 0;
/* move EOP and bytes after EOP to the end of aligned size */
move_size = pb - pb_eop;
memmove(&br->phy_buf[aligned_phy_len - move_size], pb_eop, move_size);
/* fill the hole with PHY_IDLEs */
memset(pb_eop, PHY_IDLE, aligned_phy_len - br->phy_len);
/* update the phy data length */
br->phy_len = aligned_phy_len;
return 0;
}