if (ec_dev->din_size < EC_MSG_PREAMBLE_COUNT) return -EINVAL;
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); while (true) { unsignedlong start_jiffies = jiffies;
ret = receive_n_bytes(ec_dev,
ec_dev->din,
EC_MSG_PREAMBLE_COUNT); if (ret < 0) return ret;
ptr = ec_dev->din; for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { if (*ptr == EC_SPI_FRAME_START) {
dev_dbg(ec_dev->dev, "msg found at %zd\n",
ptr - ec_dev->din); break;
}
} if (ptr != end) break;
/* *Usethetimeatthestartoftheloopasatimeout.This *givesusonelastshotatgettingthetransferandisuseful *incasewegotcontextswitchedoutforawhile.
*/ if (time_after(start_jiffies, deadline)) {
dev_warn(ec_dev->dev, "EC failed to respond in time\n"); return -ETIMEDOUT;
}
}
/* *ptrnowpointstotheheaderbyte.Copyanyvaliddatatothe *startofourbuffer
*/
todo = end - ++ptr;
todo = min(todo, need_len);
memmove(ec_dev->din, ptr, todo);
ptr = ec_dev->din + todo;
dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n",
need_len, todo);
need_len -= todo;
/* If the entire response struct wasn't read, get the rest of it. */ if (todo < sizeof(*response)) {
ret = receive_n_bytes(ec_dev, ptr, sizeof(*response) - todo); if (ret < 0) return -EBADMSG;
ptr += (sizeof(*response) - todo);
todo = sizeof(*response);
}
/* Abort if data_len is too large. */ if (response->data_len > ec_dev->din_size) return -EMSGSIZE;
/* Receive data until we have it all */ while (need_len > 0) { /* *Wecan'tsupporttransferslargerthantheSPIFIFOsize *unlesswehaveDMA.Wedon'thaveDMAontheISPSPIports *forExynos.WeneedawayofaskingSPIdriverfor *maximum-supportedtransfersize.
*/
todo = min(need_len, 256);
dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n",
todo, need_len, ptr - ec_dev->din);
ret = receive_n_bytes(ec_dev, ptr, todo); if (ret < 0) return ret;
/** *cros_ec_spi_receive_response-ReceivearesponsefromtheEC. * *Thisfunctionhastwophases:readingthepreamblebytes(sinceifweread *datafromtheECbeforeitisreadytosend,wejustgetpreamble)and *readingtheactualmessage. * *Thereceiveddataisplacedintoec_dev->din. * *@ec_dev:ChromeOSECdevice *@need_len:Numberofmessagebytesweneedtoread
*/ staticint cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, int need_len)
{
u8 *ptr, *end; int ret; unsignedlong deadline; int todo;
if (ec_dev->din_size < EC_MSG_PREAMBLE_COUNT) return -EINVAL;
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); while (true) { unsignedlong start_jiffies = jiffies;
ret = receive_n_bytes(ec_dev,
ec_dev->din,
EC_MSG_PREAMBLE_COUNT); if (ret < 0) return ret;
ptr = ec_dev->din; for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { if (*ptr == EC_SPI_FRAME_START) {
dev_dbg(ec_dev->dev, "msg found at %zd\n",
ptr - ec_dev->din); break;
}
} if (ptr != end) break;
/* *Usethetimeatthestartoftheloopasatimeout.This *givesusonelastshotatgettingthetransferandisuseful *incasewegotcontextswitchedoutforawhile.
*/ if (time_after(start_jiffies, deadline)) {
dev_warn(ec_dev->dev, "EC failed to respond in time\n"); return -ETIMEDOUT;
}
}
/* *ptrnowpointstotheheaderbyte.Copyanyvaliddatatothe *startofourbuffer
*/
todo = end - ++ptr;
todo = min(todo, need_len);
memmove(ec_dev->din, ptr, todo);
ptr = ec_dev->din + todo;
dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n",
need_len, todo);
need_len -= todo;
/* Receive data until we have it all */ while (need_len > 0) { /* *Wecan'tsupporttransferslargerthantheSPIFIFOsize *unlesswehaveDMA.Wedon'thaveDMAontheISPSPIports *forExynos.WeneedawayofaskingSPIdriverfor *maximum-supportedtransfersize.
*/
todo = min(need_len, 256);
dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n",
todo, need_len, ptr - ec_dev->din);
ret = receive_n_bytes(ec_dev, ptr, todo); if (ret < 0) return ret;
len = cros_ec_prepare_tx(ec_dev, ec_msg); if (len < 0) return len;
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
/* If it's too soon to do another transaction, wait */
delay = ktime_get_ns() - ec_spi->last_transfer_ns; if (delay < EC_SPI_RECOVERY_TIME_NS)
ndelay(EC_SPI_RECOVERY_TIME_NS - delay);
rx_buf = kzalloc(len, GFP_KERNEL); if (!rx_buf) return -ENOMEM;
ret = cros_ec_check_result(ec_dev, ec_msg); if (ret) gotoexit;
len = response->data_len;
sum = 0; if (len > ec_msg->insize) {
dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
len, ec_msg->insize);
ret = -EMSGSIZE; gotoexit;
}
for (i = 0; i < sizeof(*response); i++)
sum += ptr[i];
/* copy response packet payload and compute checksum */
memcpy(ec_msg->data, ptr + sizeof(*response), len); for (i = 0; i < len; i++)
sum += ec_msg->data[i];
if (sum) {
dev_err(ec_dev->dev, "bad packet checksum, calculated %x\n",
sum);
ret = -EBADMSG; gotoexit;
}
ret = len; exit:
kfree(rx_buf); if (ec_msg->command == EC_CMD_REBOOT_EC)
msleep(EC_REBOOT_DELAY_MS);
return ret;
}
/** *do_cros_ec_cmd_xfer_spi-TransferamessageoverSPIandreceivethereply * *@ec_dev:ChromeOSECdevice *@ec_msg:Messagetotransfer
*/ staticint do_cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, struct cros_ec_command *ec_msg)
{ struct cros_ec_spi *ec_spi = ec_dev->priv; struct spi_transfer trans; struct spi_message msg; int i, len;
u8 *ptr;
u8 *rx_buf;
u8 rx_byte; int sum; int ret = 0, final_ret; unsignedlong delay;
len = cros_ec_prepare_tx(ec_dev, ec_msg); if (len < 0) return len;
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
/* If it's too soon to do another transaction, wait */
delay = ktime_get_ns() - ec_spi->last_transfer_ns; if (delay < EC_SPI_RECOVERY_TIME_NS)
ndelay(EC_SPI_RECOVERY_TIME_NS - delay);
rx_buf = kzalloc(len, GFP_KERNEL); if (!rx_buf) return -ENOMEM;
/* Get the response */ if (!ret) { /* Verify that EC can process command */ for (i = 0; i < len; i++) {
rx_byte = rx_buf[i]; /* See comments in cros_ec_pkt_xfer_spi() */ if (rx_byte == EC_SPI_PAST_END ||
rx_byte == EC_SPI_RX_BAD_DATA ||
rx_byte == EC_SPI_NOT_READY) {
ret = -EAGAIN; break;
}
}
}
if (!ret)
ret = cros_ec_spi_receive_response(ec_dev,
ec_msg->insize + EC_MSG_TX_PROTO_BYTES); elseif (ret != -EAGAIN)
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
final_ret = terminate_request(ec_dev);
spi_bus_unlock(ec_spi->spi->controller);
if (!ret)
ret = final_ret; if (ret < 0) gotoexit;
ptr = ec_dev->din;
/* check response error code */
ec_msg->result = ptr[0];
ret = cros_ec_check_result(ec_dev, ec_msg); if (ret) gotoexit;
len = ptr[1];
sum = ptr[0] + ptr[1]; if (len > ec_msg->insize) {
dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
len, ec_msg->insize);
ret = -ENOSPC; gotoexit;
}
/* copy response packet payload and compute checksum */ for (i = 0; i < len; i++) {
sum += ptr[i + 2]; if (ec_msg->insize)
ec_msg->data[i] = ptr[i + 2];
}
sum &= 0xff;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.