in host/vub300.c [1590:1708]
static void __vub300_command_response(struct vub300_mmc_host *vub300,
struct mmc_command *cmd,
struct mmc_data *data, int data_length)
{
/* cmd_mutex is held by vub300_cmndwork_thread */
long respretval;
int msec_timeout = 1000 + data_length / 4;
respretval =
wait_for_completion_timeout(&vub300->command_complete,
msecs_to_jiffies(msec_timeout));
if (respretval == 0) { /* TIMED OUT */
/* we don't know which of "out" and "res" if any failed */
int result;
vub300->usb_timed_out = 1;
usb_kill_urb(vub300->command_out_urb);
usb_kill_urb(vub300->command_res_urb);
cmd->error = -ETIMEDOUT;
result = usb_lock_device_for_reset(vub300->udev,
vub300->interface);
if (result == 0) {
result = usb_reset_device(vub300->udev);
usb_unlock_device(vub300->udev);
}
} else if (respretval < 0) {
/* we don't know which of "out" and "res" if any failed */
usb_kill_urb(vub300->command_out_urb);
usb_kill_urb(vub300->command_res_urb);
cmd->error = respretval;
} else if (cmd->error) {
/*
* the error occurred sending the command
* or receiving the response
*/
} else if (vub300->command_out_urb->status) {
vub300->usb_transport_fail = vub300->command_out_urb->status;
cmd->error = -EPROTO == vub300->command_out_urb->status ?
-ESHUTDOWN : vub300->command_out_urb->status;
} else if (vub300->command_res_urb->status) {
vub300->usb_transport_fail = vub300->command_res_urb->status;
cmd->error = -EPROTO == vub300->command_res_urb->status ?
-ESHUTDOWN : vub300->command_res_urb->status;
} else if (vub300->resp.common.header_type == 0x00) {
/*
* the command completed successfully
* and there was no piggybacked data
*/
} else if (vub300->resp.common.header_type == RESPONSE_ERROR) {
cmd->error =
vub300_response_error(vub300->resp.error.error_code);
if (vub300->data)
usb_sg_cancel(&vub300->sg_request);
} else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) {
int offloaded_data_length =
vub300->resp.common.header_size -
sizeof(struct sd_register_header);
int register_count = offloaded_data_length >> 3;
int ri = 0;
while (register_count--) {
add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
ri += 1;
}
vub300->resp.common.header_size =
sizeof(struct sd_register_header);
vub300->resp.common.header_type = 0x00;
cmd->error = 0;
} else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) {
int offloaded_data_length =
vub300->resp.common.header_size -
sizeof(struct sd_register_header);
int register_count = offloaded_data_length >> 3;
int ri = 0;
while (register_count--) {
add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
ri += 1;
}
mutex_lock(&vub300->irq_mutex);
if (vub300->irqs_queued) {
vub300->irqs_queued += 1;
} else if (vub300->irq_enabled) {
vub300->irqs_queued += 1;
vub300_queue_poll_work(vub300, 0);
} else {
vub300->irqs_queued += 1;
}
vub300->irq_disabled = 1;
mutex_unlock(&vub300->irq_mutex);
vub300->resp.common.header_size =
sizeof(struct sd_register_header);
vub300->resp.common.header_type = 0x00;
cmd->error = 0;
} else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) {
int offloaded_data_length =
vub300->resp.common.header_size -
sizeof(struct sd_register_header);
int register_count = offloaded_data_length >> 3;
int ri = 0;
while (register_count--) {
add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
ri += 1;
}
mutex_lock(&vub300->irq_mutex);
if (vub300->irqs_queued) {
vub300->irqs_queued += 1;
} else if (vub300->irq_enabled) {
vub300->irqs_queued += 1;
vub300_queue_poll_work(vub300, 0);
} else {
vub300->irqs_queued += 1;
}
vub300->irq_disabled = 0;
mutex_unlock(&vub300->irq_mutex);
vub300->resp.common.header_size =
sizeof(struct sd_register_header);
vub300->resp.common.header_type = 0x00;
cmd->error = 0;
} else {
cmd->error = -EINVAL;
}
}