in hid-mcp2221.c [710:822]
static int mcp2221_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size)
{
u8 *buf;
struct mcp2221 *mcp = hid_get_drvdata(hdev);
switch (data[0]) {
case MCP2221_I2C_WR_DATA:
case MCP2221_I2C_WR_NO_STOP:
case MCP2221_I2C_RD_DATA:
case MCP2221_I2C_RD_RPT_START:
switch (data[1]) {
case MCP2221_SUCCESS:
mcp->status = 0;
break;
default:
mcp->status = mcp_get_i2c_eng_state(mcp, data, 2);
}
complete(&mcp->wait_in_report);
break;
case MCP2221_I2C_PARAM_OR_STATUS:
switch (data[1]) {
case MCP2221_SUCCESS:
if ((mcp->txbuf[3] == MCP2221_I2C_SET_SPEED) &&
(data[3] != MCP2221_I2C_SET_SPEED)) {
mcp->status = -EAGAIN;
break;
}
if (data[20] & MCP2221_I2C_MASK_ADDR_NACK) {
mcp->status = -ENXIO;
break;
}
mcp->status = mcp_get_i2c_eng_state(mcp, data, 8);
break;
default:
mcp->status = -EIO;
}
complete(&mcp->wait_in_report);
break;
case MCP2221_I2C_GET_DATA:
switch (data[1]) {
case MCP2221_SUCCESS:
if (data[2] == MCP2221_I2C_ADDR_NACK) {
mcp->status = -ENXIO;
break;
}
if (!mcp_get_i2c_eng_state(mcp, data, 2)
&& (data[3] == 0)) {
mcp->status = 0;
break;
}
if (data[3] == 127) {
mcp->status = -EIO;
break;
}
if (data[2] == MCP2221_I2C_READ_COMPL) {
buf = mcp->rxbuf;
memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
mcp->status = 0;
break;
}
mcp->status = -EIO;
break;
default:
mcp->status = -EIO;
}
complete(&mcp->wait_in_report);
break;
case MCP2221_GPIO_GET:
switch (data[1]) {
case MCP2221_SUCCESS:
if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
(data[mcp->gp_idx + 1] == MCP2221_ALT_F_NOT_GPIOD)) {
mcp->status = -ENOENT;
} else {
mcp->status = !!data[mcp->gp_idx];
mcp->gpio_dir = data[mcp->gp_idx + 1];
}
break;
default:
mcp->status = -EAGAIN;
}
complete(&mcp->wait_in_report);
break;
case MCP2221_GPIO_SET:
switch (data[1]) {
case MCP2221_SUCCESS:
if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
(data[mcp->gp_idx - 1] == MCP2221_ALT_F_NOT_GPIOV)) {
mcp->status = -ENOENT;
} else {
mcp->status = 0;
}
break;
default:
mcp->status = -EAGAIN;
}
complete(&mcp->wait_in_report);
break;
default:
mcp->status = -EIO;
complete(&mcp->wait_in_report);
}
return 1;
}