static void __vub300_command_response()

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;
	}
}