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