/* * Returns a negative error value in case of an error, 0 if processing of * the firmware should be stopped after this action, 1 otherwise. */ static int process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) { size_t len = sigma_action_len(sa); int ret; pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, sa->instr, sa->addr, len); switch (sa->instr) { case SIGMA_ACTION_WRITEXBYTES: case SIGMA_ACTION_WRITESINGLE: case SIGMA_ACTION_WRITESAFELOAD: ret = ssfw->write(ssfw->control_data, sa, len); if (ret < 0) return -EINVAL; break; case SIGMA_ACTION_DELAY: udelay(len); len = 0; break; case SIGMA_ACTION_END: return 0; default: return -EINVAL; } return 1; }
static size_t sigma_action_size(struct sigma_action *sa) { size_t payload = 0; switch (sa->instr) { case SIGMA_ACTION_WRITEXBYTES: case SIGMA_ACTION_WRITESINGLE: case SIGMA_ACTION_WRITESAFELOAD: payload = sigma_action_len(sa); break; default: break; } payload = ALIGN(payload, 2); return payload + sizeof(struct sigma_action); }
/* Return: 0==OK, <0==error, =1 ==no more actions */ static int process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) { struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos); size_t len = sigma_action_len(sa); int ret = 0; pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, sa->instr, sa->addr, len); switch (sa->instr) { case SIGMA_ACTION_WRITEXBYTES: case SIGMA_ACTION_WRITESINGLE: case SIGMA_ACTION_WRITESAFELOAD: if (ssfw->fw->size < ssfw->pos + len) return -EINVAL; ret = i2c_master_send(client, (void *)&sa->addr, len); if (ret < 0) return -EINVAL; break; case SIGMA_ACTION_DELAY: ret = 0; udelay(len); len = 0; break; case SIGMA_ACTION_END: return 1; default: return -EINVAL; } /* when arrive here ret=0 or sent data */ ssfw->pos += sigma_action_size(sa, len); return ssfw->pos == ssfw->fw->size; }