static void send_command()

in host/vub300.c [889:1175]


static void send_command(struct vub300_mmc_host *vub300)
{
	/* cmd_mutex is held by vub300_cmndwork_thread */
	struct mmc_command *cmd = vub300->cmd;
	struct mmc_data *data = vub300->data;
	int retval;
	int i;
	u8 response_type;
	if (vub300->app_spec) {
		switch (cmd->opcode) {
		case 6:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			if (0x00000000 == (0x00000003 & cmd->arg))
				vub300->bus_width = 1;
			else if (0x00000002 == (0x00000003 & cmd->arg))
				vub300->bus_width = 4;
			else
				dev_err(&vub300->udev->dev,
					"unexpected ACMD6 bus_width=%d\n",
					0x00000003 & cmd->arg);
			break;
		case 13:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 22:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 23:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 41:
			response_type = SDRT_3;
			vub300->resp_len = 6;
			break;
		case 42:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 51:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 55:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		default:
			vub300->resp_len = 0;
			cmd->error = -EINVAL;
			complete(&vub300->command_complete);
			return;
		}
		vub300->app_spec = 0;
	} else {
		switch (cmd->opcode) {
		case 0:
			response_type = SDRT_NONE;
			vub300->resp_len = 0;
			break;
		case 1:
			response_type = SDRT_3;
			vub300->resp_len = 6;
			break;
		case 2:
			response_type = SDRT_2;
			vub300->resp_len = 17;
			break;
		case 3:
			response_type = SDRT_6;
			vub300->resp_len = 6;
			break;
		case 4:
			response_type = SDRT_NONE;
			vub300->resp_len = 0;
			break;
		case 5:
			response_type = SDRT_4;
			vub300->resp_len = 6;
			break;
		case 6:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 7:
			response_type = SDRT_1B;
			vub300->resp_len = 6;
			break;
		case 8:
			response_type = SDRT_7;
			vub300->resp_len = 6;
			break;
		case 9:
			response_type = SDRT_2;
			vub300->resp_len = 17;
			break;
		case 10:
			response_type = SDRT_2;
			vub300->resp_len = 17;
			break;
		case 12:
			response_type = SDRT_1B;
			vub300->resp_len = 6;
			break;
		case 13:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 15:
			response_type = SDRT_NONE;
			vub300->resp_len = 0;
			break;
		case 16:
			for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
				vub300->fbs[i] = 0xFFFF & cmd->arg;
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 17:
		case 18:
		case 24:
		case 25:
		case 27:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 28:
		case 29:
			response_type = SDRT_1B;
			vub300->resp_len = 6;
			break;
		case 30:
		case 32:
		case 33:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 38:
			response_type = SDRT_1B;
			vub300->resp_len = 6;
			break;
		case 42:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		case 52:
			response_type = SDRT_5;
			vub300->resp_len = 6;
			snoop_block_size_and_bus_width(vub300, cmd->arg);
			break;
		case 53:
			response_type = SDRT_5;
			vub300->resp_len = 6;
			break;
		case 55:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			vub300->app_spec = 1;
			break;
		case 56:
			response_type = SDRT_1;
			vub300->resp_len = 6;
			break;
		default:
			vub300->resp_len = 0;
			cmd->error = -EINVAL;
			complete(&vub300->command_complete);
			return;
		}
	}
	/*
	 * it is a shame that we can not use "sizeof(struct sd_command_header)"
	 * this is because the packet _must_ be padded to 64 bytes
	 */
	vub300->cmnd.head.header_size = 20;
	vub300->cmnd.head.header_type = 0x00;
	vub300->cmnd.head.port_number = 0; /* "0" means port 1 */
	vub300->cmnd.head.command_type = 0x00; /* standard read command */
	vub300->cmnd.head.response_type = response_type;
	vub300->cmnd.head.command_index = cmd->opcode;
	vub300->cmnd.head.arguments[0] = cmd->arg >> 24;
	vub300->cmnd.head.arguments[1] = cmd->arg >> 16;
	vub300->cmnd.head.arguments[2] = cmd->arg >> 8;
	vub300->cmnd.head.arguments[3] = cmd->arg >> 0;
	if (cmd->opcode == 52) {
		int fn = 0x7 & (cmd->arg >> 28);
		vub300->cmnd.head.block_count[0] = 0;
		vub300->cmnd.head.block_count[1] = 0;
		vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF;
		vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF;
		vub300->cmnd.head.command_type = 0x00;
		vub300->cmnd.head.transfer_size[0] = 0;
		vub300->cmnd.head.transfer_size[1] = 0;
		vub300->cmnd.head.transfer_size[2] = 0;
		vub300->cmnd.head.transfer_size[3] = 0;
	} else if (!data) {
		vub300->cmnd.head.block_count[0] = 0;
		vub300->cmnd.head.block_count[1] = 0;
		vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF;
		vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF;
		vub300->cmnd.head.command_type = 0x00;
		vub300->cmnd.head.transfer_size[0] = 0;
		vub300->cmnd.head.transfer_size[1] = 0;
		vub300->cmnd.head.transfer_size[2] = 0;
		vub300->cmnd.head.transfer_size[3] = 0;
	} else if (cmd->opcode == 53) {
		int fn = 0x7 & (cmd->arg >> 28);
		if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */
			vub300->cmnd.head.block_count[0] =
				(data->blocks >> 8) & 0xFF;
			vub300->cmnd.head.block_count[1] =
				(data->blocks >> 0) & 0xFF;
			vub300->cmnd.head.block_size[0] =
				(data->blksz >> 8) & 0xFF;
			vub300->cmnd.head.block_size[1] =
				(data->blksz >> 0) & 0xFF;
		} else {	/* BYTE MODE */
			vub300->cmnd.head.block_count[0] = 0;
			vub300->cmnd.head.block_count[1] = 0;
			vub300->cmnd.head.block_size[0] =
				(vub300->datasize >> 8) & 0xFF;
			vub300->cmnd.head.block_size[1] =
				(vub300->datasize >> 0) & 0xFF;
		}
		vub300->cmnd.head.command_type =
			(MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
		vub300->cmnd.head.transfer_size[0] =
			(vub300->datasize >> 24) & 0xFF;
		vub300->cmnd.head.transfer_size[1] =
			(vub300->datasize >> 16) & 0xFF;
		vub300->cmnd.head.transfer_size[2] =
			(vub300->datasize >> 8) & 0xFF;
		vub300->cmnd.head.transfer_size[3] =
			(vub300->datasize >> 0) & 0xFF;
		if (vub300->datasize < vub300->fbs[fn]) {
			vub300->cmnd.head.block_count[0] = 0;
			vub300->cmnd.head.block_count[1] = 0;
		}
	} else {
		vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF;
		vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF;
		vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF;
		vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF;
		vub300->cmnd.head.command_type =
			(MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
		vub300->cmnd.head.transfer_size[0] =
			(vub300->datasize >> 24) & 0xFF;
		vub300->cmnd.head.transfer_size[1] =
			(vub300->datasize >> 16) & 0xFF;
		vub300->cmnd.head.transfer_size[2] =
			(vub300->datasize >> 8) & 0xFF;
		vub300->cmnd.head.transfer_size[3] =
			(vub300->datasize >> 0) & 0xFF;
		if (vub300->datasize < vub300->fbs[0]) {
			vub300->cmnd.head.block_count[0] = 0;
			vub300->cmnd.head.block_count[1] = 0;
		}
	}
	if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) {
		u16 block_size = vub300->cmnd.head.block_size[1] |
			(vub300->cmnd.head.block_size[0] << 8);
		u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY -
			(FIRMWARE_BLOCK_BOUNDARY % block_size);
		vub300->cmnd.head.block_boundary[0] =
			(block_boundary >> 8) & 0xFF;
		vub300->cmnd.head.block_boundary[1] =
			(block_boundary >> 0) & 0xFF;
	} else {
		vub300->cmnd.head.block_boundary[0] = 0;
		vub300->cmnd.head.block_boundary[1] = 0;
	}
	usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
			  usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep),
			  &vub300->cmnd, sizeof(vub300->cmnd),
			  command_out_completed, vub300);
	retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
	if (retval < 0) {
		cmd->error = retval;
		complete(&vub300->command_complete);
		return;
	} else {
		return;
	}
}