162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Remote VUB300 SDIO/SDmem Host Controller Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010 Elan Digital Systems Limited
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * based on USB Skeleton driver - 2.2
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot
1262306a36Sopenharmony_ci *         Any SDIO/SDmem/MMC device plugged into the VUB300 will appear,
1362306a36Sopenharmony_ci *         by virtue of this driver, to have been plugged into a local
1462306a36Sopenharmony_ci *         SDIO host controller, similar to, say, a PCI Ricoh controller
1562306a36Sopenharmony_ci *         This is because this kernel device driver is both a USB 2.0
1662306a36Sopenharmony_ci *         client device driver AND an MMC host controller driver. Thus
1762306a36Sopenharmony_ci *         if there is an existing driver for the inserted SDIO/SDmem/MMC
1862306a36Sopenharmony_ci *         device then that driver will be used by the kernel to manage
1962306a36Sopenharmony_ci *         the device in exactly the same fashion as if it had been
2062306a36Sopenharmony_ci *         directly plugged into, say, a local pci bus Ricoh controller
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * RANT: this driver was written using a display 128x48 - converting it
2362306a36Sopenharmony_ci *       to a line width of 80 makes it very difficult to support. In
2462306a36Sopenharmony_ci *       particular functions have been broken down into sub functions
2562306a36Sopenharmony_ci *       and the original meaningful names have been shortened into
2662306a36Sopenharmony_ci *       cryptic ones.
2762306a36Sopenharmony_ci *       The problem is that executing a fragment of code subject to
2862306a36Sopenharmony_ci *       two conditions means an indentation of 24, thus leaving only
2962306a36Sopenharmony_ci *       56 characters for a C statement. And that is quite ridiculous!
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * Data types: data passed to/from the VUB300 is fixed to a number of
3262306a36Sopenharmony_ci *             bits and driver data fields reflect that limit by using
3362306a36Sopenharmony_ci *             u8, u16, u32
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci#include <linux/kernel.h>
3662306a36Sopenharmony_ci#include <linux/errno.h>
3762306a36Sopenharmony_ci#include <linux/init.h>
3862306a36Sopenharmony_ci#include <linux/slab.h>
3962306a36Sopenharmony_ci#include <linux/module.h>
4062306a36Sopenharmony_ci#include <linux/kref.h>
4162306a36Sopenharmony_ci#include <linux/uaccess.h>
4262306a36Sopenharmony_ci#include <linux/usb.h>
4362306a36Sopenharmony_ci#include <linux/mutex.h>
4462306a36Sopenharmony_ci#include <linux/mmc/host.h>
4562306a36Sopenharmony_ci#include <linux/mmc/card.h>
4662306a36Sopenharmony_ci#include <linux/mmc/sdio_func.h>
4762306a36Sopenharmony_ci#include <linux/mmc/sdio_ids.h>
4862306a36Sopenharmony_ci#include <linux/workqueue.h>
4962306a36Sopenharmony_ci#include <linux/ctype.h>
5062306a36Sopenharmony_ci#include <linux/firmware.h>
5162306a36Sopenharmony_ci#include <linux/scatterlist.h>
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct host_controller_info {
5462306a36Sopenharmony_ci	u8 info_size;
5562306a36Sopenharmony_ci	u16 firmware_version;
5662306a36Sopenharmony_ci	u8 number_of_ports;
5762306a36Sopenharmony_ci} __packed;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define FIRMWARE_BLOCK_BOUNDARY 1024
6062306a36Sopenharmony_cistruct sd_command_header {
6162306a36Sopenharmony_ci	u8 header_size;
6262306a36Sopenharmony_ci	u8 header_type;
6362306a36Sopenharmony_ci	u8 port_number;
6462306a36Sopenharmony_ci	u8 command_type; /* Bit7 - Rd/Wr */
6562306a36Sopenharmony_ci	u8 command_index;
6662306a36Sopenharmony_ci	u8 transfer_size[4]; /* ReadSize + ReadSize */
6762306a36Sopenharmony_ci	u8 response_type;
6862306a36Sopenharmony_ci	u8 arguments[4];
6962306a36Sopenharmony_ci	u8 block_count[2];
7062306a36Sopenharmony_ci	u8 block_size[2];
7162306a36Sopenharmony_ci	u8 block_boundary[2];
7262306a36Sopenharmony_ci	u8 reserved[44]; /* to pad out to 64 bytes */
7362306a36Sopenharmony_ci} __packed;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistruct sd_irqpoll_header {
7662306a36Sopenharmony_ci	u8 header_size;
7762306a36Sopenharmony_ci	u8 header_type;
7862306a36Sopenharmony_ci	u8 port_number;
7962306a36Sopenharmony_ci	u8 command_type; /* Bit7 - Rd/Wr */
8062306a36Sopenharmony_ci	u8 padding[16]; /* don't ask why !! */
8162306a36Sopenharmony_ci	u8 poll_timeout_msb;
8262306a36Sopenharmony_ci	u8 poll_timeout_lsb;
8362306a36Sopenharmony_ci	u8 reserved[42]; /* to pad out to 64 bytes */
8462306a36Sopenharmony_ci} __packed;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct sd_common_header {
8762306a36Sopenharmony_ci	u8 header_size;
8862306a36Sopenharmony_ci	u8 header_type;
8962306a36Sopenharmony_ci	u8 port_number;
9062306a36Sopenharmony_ci} __packed;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct sd_response_header {
9362306a36Sopenharmony_ci	u8 header_size;
9462306a36Sopenharmony_ci	u8 header_type;
9562306a36Sopenharmony_ci	u8 port_number;
9662306a36Sopenharmony_ci	u8 command_type;
9762306a36Sopenharmony_ci	u8 command_index;
9862306a36Sopenharmony_ci	u8 command_response[];
9962306a36Sopenharmony_ci} __packed;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistruct sd_status_header {
10262306a36Sopenharmony_ci	u8 header_size;
10362306a36Sopenharmony_ci	u8 header_type;
10462306a36Sopenharmony_ci	u8 port_number;
10562306a36Sopenharmony_ci	u16 port_flags;
10662306a36Sopenharmony_ci	u32 sdio_clock;
10762306a36Sopenharmony_ci	u16 host_header_size;
10862306a36Sopenharmony_ci	u16 func_header_size;
10962306a36Sopenharmony_ci	u16 ctrl_header_size;
11062306a36Sopenharmony_ci} __packed;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistruct sd_error_header {
11362306a36Sopenharmony_ci	u8 header_size;
11462306a36Sopenharmony_ci	u8 header_type;
11562306a36Sopenharmony_ci	u8 port_number;
11662306a36Sopenharmony_ci	u8 error_code;
11762306a36Sopenharmony_ci} __packed;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct sd_interrupt_header {
12062306a36Sopenharmony_ci	u8 header_size;
12162306a36Sopenharmony_ci	u8 header_type;
12262306a36Sopenharmony_ci	u8 port_number;
12362306a36Sopenharmony_ci} __packed;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistruct offload_registers_access {
12662306a36Sopenharmony_ci	u8 command_byte[4];
12762306a36Sopenharmony_ci	u8 Respond_Byte[4];
12862306a36Sopenharmony_ci} __packed;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define INTERRUPT_REGISTER_ACCESSES 15
13162306a36Sopenharmony_cistruct sd_offloaded_interrupt {
13262306a36Sopenharmony_ci	u8 header_size;
13362306a36Sopenharmony_ci	u8 header_type;
13462306a36Sopenharmony_ci	u8 port_number;
13562306a36Sopenharmony_ci	struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES];
13662306a36Sopenharmony_ci} __packed;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistruct sd_register_header {
13962306a36Sopenharmony_ci	u8 header_size;
14062306a36Sopenharmony_ci	u8 header_type;
14162306a36Sopenharmony_ci	u8 port_number;
14262306a36Sopenharmony_ci	u8 command_type;
14362306a36Sopenharmony_ci	u8 command_index;
14462306a36Sopenharmony_ci	u8 command_response[6];
14562306a36Sopenharmony_ci} __packed;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define PIGGYBACK_REGISTER_ACCESSES 14
14862306a36Sopenharmony_cistruct sd_offloaded_piggyback {
14962306a36Sopenharmony_ci	struct sd_register_header sdio;
15062306a36Sopenharmony_ci	struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES];
15162306a36Sopenharmony_ci} __packed;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciunion sd_response {
15462306a36Sopenharmony_ci	struct sd_common_header common;
15562306a36Sopenharmony_ci	struct sd_status_header status;
15662306a36Sopenharmony_ci	struct sd_error_header error;
15762306a36Sopenharmony_ci	struct sd_interrupt_header interrupt;
15862306a36Sopenharmony_ci	struct sd_response_header response;
15962306a36Sopenharmony_ci	struct sd_offloaded_interrupt irq;
16062306a36Sopenharmony_ci	struct sd_offloaded_piggyback pig;
16162306a36Sopenharmony_ci} __packed;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciunion sd_command {
16462306a36Sopenharmony_ci	struct sd_command_header head;
16562306a36Sopenharmony_ci	struct sd_irqpoll_header poll;
16662306a36Sopenharmony_ci} __packed;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cienum SD_RESPONSE_TYPE {
16962306a36Sopenharmony_ci	SDRT_UNSPECIFIED = 0,
17062306a36Sopenharmony_ci	SDRT_NONE,
17162306a36Sopenharmony_ci	SDRT_1,
17262306a36Sopenharmony_ci	SDRT_1B,
17362306a36Sopenharmony_ci	SDRT_2,
17462306a36Sopenharmony_ci	SDRT_3,
17562306a36Sopenharmony_ci	SDRT_4,
17662306a36Sopenharmony_ci	SDRT_5,
17762306a36Sopenharmony_ci	SDRT_5B,
17862306a36Sopenharmony_ci	SDRT_6,
17962306a36Sopenharmony_ci	SDRT_7,
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define RESPONSE_INTERRUPT			0x01
18362306a36Sopenharmony_ci#define RESPONSE_ERROR				0x02
18462306a36Sopenharmony_ci#define RESPONSE_STATUS				0x03
18562306a36Sopenharmony_ci#define RESPONSE_IRQ_DISABLED			0x05
18662306a36Sopenharmony_ci#define RESPONSE_IRQ_ENABLED			0x06
18762306a36Sopenharmony_ci#define RESPONSE_PIGGYBACKED			0x07
18862306a36Sopenharmony_ci#define RESPONSE_NO_INTERRUPT			0x08
18962306a36Sopenharmony_ci#define RESPONSE_PIG_DISABLED			0x09
19062306a36Sopenharmony_ci#define RESPONSE_PIG_ENABLED			0x0A
19162306a36Sopenharmony_ci#define SD_ERROR_1BIT_TIMEOUT			0x01
19262306a36Sopenharmony_ci#define SD_ERROR_4BIT_TIMEOUT			0x02
19362306a36Sopenharmony_ci#define SD_ERROR_1BIT_CRC_WRONG			0x03
19462306a36Sopenharmony_ci#define SD_ERROR_4BIT_CRC_WRONG			0x04
19562306a36Sopenharmony_ci#define SD_ERROR_1BIT_CRC_ERROR			0x05
19662306a36Sopenharmony_ci#define SD_ERROR_4BIT_CRC_ERROR			0x06
19762306a36Sopenharmony_ci#define SD_ERROR_NO_CMD_ENDBIT			0x07
19862306a36Sopenharmony_ci#define SD_ERROR_NO_1BIT_DATEND			0x08
19962306a36Sopenharmony_ci#define SD_ERROR_NO_4BIT_DATEND			0x09
20062306a36Sopenharmony_ci#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT	0x0A
20162306a36Sopenharmony_ci#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT	0x0B
20262306a36Sopenharmony_ci#define SD_ERROR_ILLEGAL_COMMAND		0x0C
20362306a36Sopenharmony_ci#define SD_ERROR_NO_DEVICE			0x0D
20462306a36Sopenharmony_ci#define SD_ERROR_TRANSFER_LENGTH		0x0E
20562306a36Sopenharmony_ci#define SD_ERROR_1BIT_DATA_TIMEOUT		0x0F
20662306a36Sopenharmony_ci#define SD_ERROR_4BIT_DATA_TIMEOUT		0x10
20762306a36Sopenharmony_ci#define SD_ERROR_ILLEGAL_STATE			0x11
20862306a36Sopenharmony_ci#define SD_ERROR_UNKNOWN_ERROR			0x12
20962306a36Sopenharmony_ci#define SD_ERROR_RESERVED_ERROR			0x13
21062306a36Sopenharmony_ci#define SD_ERROR_INVALID_FUNCTION		0x14
21162306a36Sopenharmony_ci#define SD_ERROR_OUT_OF_RANGE			0x15
21262306a36Sopenharmony_ci#define SD_ERROR_STAT_CMD			0x16
21362306a36Sopenharmony_ci#define SD_ERROR_STAT_DATA			0x17
21462306a36Sopenharmony_ci#define SD_ERROR_STAT_CMD_TIMEOUT		0x18
21562306a36Sopenharmony_ci#define SD_ERROR_SDCRDY_STUCK			0x19
21662306a36Sopenharmony_ci#define SD_ERROR_UNHANDLED			0x1A
21762306a36Sopenharmony_ci#define SD_ERROR_OVERRUN			0x1B
21862306a36Sopenharmony_ci#define SD_ERROR_PIO_TIMEOUT			0x1C
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define FUN(c) (0x000007 & (c->arg>>28))
22162306a36Sopenharmony_ci#define REG(c) (0x01FFFF & (c->arg>>9))
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic bool limit_speed_to_24_MHz;
22462306a36Sopenharmony_cimodule_param(limit_speed_to_24_MHz, bool, 0644);
22562306a36Sopenharmony_ciMODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic bool pad_input_to_usb_pkt;
22862306a36Sopenharmony_cimodule_param(pad_input_to_usb_pkt, bool, 0644);
22962306a36Sopenharmony_ciMODULE_PARM_DESC(pad_input_to_usb_pkt,
23062306a36Sopenharmony_ci		 "Pad USB data input transfers to whole USB Packet");
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic bool disable_offload_processing;
23362306a36Sopenharmony_cimodule_param(disable_offload_processing, bool, 0644);
23462306a36Sopenharmony_ciMODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic bool force_1_bit_data_xfers;
23762306a36Sopenharmony_cimodule_param(force_1_bit_data_xfers, bool, 0644);
23862306a36Sopenharmony_ciMODULE_PARM_DESC(force_1_bit_data_xfers,
23962306a36Sopenharmony_ci		 "Force SDIO Data Transfers to 1-bit Mode");
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic bool force_polling_for_irqs;
24262306a36Sopenharmony_cimodule_param(force_polling_for_irqs, bool, 0644);
24362306a36Sopenharmony_ciMODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int firmware_irqpoll_timeout = 1024;
24662306a36Sopenharmony_cimodule_param(firmware_irqpoll_timeout, int, 0644);
24762306a36Sopenharmony_ciMODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout");
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int force_max_req_size = 128;
25062306a36Sopenharmony_cimodule_param(force_max_req_size, int, 0644);
25162306a36Sopenharmony_ciMODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes");
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#ifdef SMSC_DEVELOPMENT_BOARD
25462306a36Sopenharmony_cistatic int firmware_rom_wait_states = 0x04;
25562306a36Sopenharmony_ci#else
25662306a36Sopenharmony_cistatic int firmware_rom_wait_states = 0x1C;
25762306a36Sopenharmony_ci#endif
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cimodule_param(firmware_rom_wait_states, int, 0644);
26062306a36Sopenharmony_ciMODULE_PARM_DESC(firmware_rom_wait_states,
26162306a36Sopenharmony_ci		 "ROM wait states byte=RRRIIEEE (Reserved Internal External)");
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#define ELAN_VENDOR_ID		0x2201
26462306a36Sopenharmony_ci#define VUB300_VENDOR_ID	0x0424
26562306a36Sopenharmony_ci#define VUB300_PRODUCT_ID	0x012C
26662306a36Sopenharmony_cistatic const struct usb_device_id vub300_table[] = {
26762306a36Sopenharmony_ci	{USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
26862306a36Sopenharmony_ci	{USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
26962306a36Sopenharmony_ci	{} /* Terminating entry */
27062306a36Sopenharmony_ci};
27162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, vub300_table);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic struct workqueue_struct *cmndworkqueue;
27462306a36Sopenharmony_cistatic struct workqueue_struct *pollworkqueue;
27562306a36Sopenharmony_cistatic struct workqueue_struct *deadworkqueue;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic inline int interface_to_InterfaceNumber(struct usb_interface *interface)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	if (!interface)
28062306a36Sopenharmony_ci		return -1;
28162306a36Sopenharmony_ci	if (!interface->cur_altsetting)
28262306a36Sopenharmony_ci		return -1;
28362306a36Sopenharmony_ci	return interface->cur_altsetting->desc.bInterfaceNumber;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistruct sdio_register {
28762306a36Sopenharmony_ci	unsigned func_num:3;
28862306a36Sopenharmony_ci	unsigned sdio_reg:17;
28962306a36Sopenharmony_ci	unsigned activate:1;
29062306a36Sopenharmony_ci	unsigned prepared:1;
29162306a36Sopenharmony_ci	unsigned regvalue:8;
29262306a36Sopenharmony_ci	unsigned response:8;
29362306a36Sopenharmony_ci	unsigned sparebit:26;
29462306a36Sopenharmony_ci};
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistruct vub300_mmc_host {
29762306a36Sopenharmony_ci	struct usb_device *udev;
29862306a36Sopenharmony_ci	struct usb_interface *interface;
29962306a36Sopenharmony_ci	struct kref kref;
30062306a36Sopenharmony_ci	struct mutex cmd_mutex;
30162306a36Sopenharmony_ci	struct mutex irq_mutex;
30262306a36Sopenharmony_ci	char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */
30362306a36Sopenharmony_ci	u8 cmnd_out_ep; /* EndPoint for commands */
30462306a36Sopenharmony_ci	u8 cmnd_res_ep; /* EndPoint for responses */
30562306a36Sopenharmony_ci	u8 data_out_ep; /* EndPoint for out data */
30662306a36Sopenharmony_ci	u8 data_inp_ep; /* EndPoint for inp data */
30762306a36Sopenharmony_ci	bool card_powered;
30862306a36Sopenharmony_ci	bool card_present;
30962306a36Sopenharmony_ci	bool read_only;
31062306a36Sopenharmony_ci	bool large_usb_packets;
31162306a36Sopenharmony_ci	bool app_spec; /* ApplicationSpecific */
31262306a36Sopenharmony_ci	bool irq_enabled; /* by the MMC CORE */
31362306a36Sopenharmony_ci	bool irq_disabled; /* in the firmware */
31462306a36Sopenharmony_ci	unsigned bus_width:4;
31562306a36Sopenharmony_ci	u8 total_offload_count;
31662306a36Sopenharmony_ci	u8 dynamic_register_count;
31762306a36Sopenharmony_ci	u8 resp_len;
31862306a36Sopenharmony_ci	u32 datasize;
31962306a36Sopenharmony_ci	int errors;
32062306a36Sopenharmony_ci	int usb_transport_fail;
32162306a36Sopenharmony_ci	int usb_timed_out;
32262306a36Sopenharmony_ci	int irqs_queued;
32362306a36Sopenharmony_ci	struct sdio_register sdio_register[16];
32462306a36Sopenharmony_ci	struct offload_interrupt_function_register {
32562306a36Sopenharmony_ci#define MAXREGBITS 4
32662306a36Sopenharmony_ci#define MAXREGS (1<<MAXREGBITS)
32762306a36Sopenharmony_ci#define MAXREGMASK (MAXREGS-1)
32862306a36Sopenharmony_ci		u8 offload_count;
32962306a36Sopenharmony_ci		u32 offload_point;
33062306a36Sopenharmony_ci		struct offload_registers_access reg[MAXREGS];
33162306a36Sopenharmony_ci	} fn[8];
33262306a36Sopenharmony_ci	u16 fbs[8]; /* Function Block Size */
33362306a36Sopenharmony_ci	struct mmc_command *cmd;
33462306a36Sopenharmony_ci	struct mmc_request *req;
33562306a36Sopenharmony_ci	struct mmc_data *data;
33662306a36Sopenharmony_ci	struct mmc_host *mmc;
33762306a36Sopenharmony_ci	struct urb *urb;
33862306a36Sopenharmony_ci	struct urb *command_out_urb;
33962306a36Sopenharmony_ci	struct urb *command_res_urb;
34062306a36Sopenharmony_ci	struct completion command_complete;
34162306a36Sopenharmony_ci	struct completion irqpoll_complete;
34262306a36Sopenharmony_ci	union sd_command cmnd;
34362306a36Sopenharmony_ci	union sd_response resp;
34462306a36Sopenharmony_ci	struct timer_list sg_transfer_timer;
34562306a36Sopenharmony_ci	struct usb_sg_request sg_request;
34662306a36Sopenharmony_ci	struct timer_list inactivity_timer;
34762306a36Sopenharmony_ci	struct work_struct deadwork;
34862306a36Sopenharmony_ci	struct work_struct cmndwork;
34962306a36Sopenharmony_ci	struct delayed_work pollwork;
35062306a36Sopenharmony_ci	struct host_controller_info hc_info;
35162306a36Sopenharmony_ci	struct sd_status_header system_port_status;
35262306a36Sopenharmony_ci	u8 padded_buffer[64];
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref)
35662306a36Sopenharmony_ci#define SET_TRANSFER_PSEUDOCODE		21
35762306a36Sopenharmony_ci#define SET_INTERRUPT_PSEUDOCODE	20
35862306a36Sopenharmony_ci#define SET_FAILURE_MODE		18
35962306a36Sopenharmony_ci#define SET_ROM_WAIT_STATES		16
36062306a36Sopenharmony_ci#define SET_IRQ_ENABLE			13
36162306a36Sopenharmony_ci#define SET_CLOCK_SPEED			11
36262306a36Sopenharmony_ci#define SET_FUNCTION_BLOCK_SIZE		9
36362306a36Sopenharmony_ci#define SET_SD_DATA_MODE		6
36462306a36Sopenharmony_ci#define SET_SD_POWER			4
36562306a36Sopenharmony_ci#define ENTER_DFU_MODE			3
36662306a36Sopenharmony_ci#define GET_HC_INF0			1
36762306a36Sopenharmony_ci#define GET_SYSTEM_PORT_STATUS		0
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void vub300_delete(struct kref *kref)
37062306a36Sopenharmony_ci{				/* kref callback - softirq */
37162306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
37262306a36Sopenharmony_ci	struct mmc_host *mmc = vub300->mmc;
37362306a36Sopenharmony_ci	usb_free_urb(vub300->command_out_urb);
37462306a36Sopenharmony_ci	vub300->command_out_urb = NULL;
37562306a36Sopenharmony_ci	usb_free_urb(vub300->command_res_urb);
37662306a36Sopenharmony_ci	vub300->command_res_urb = NULL;
37762306a36Sopenharmony_ci	usb_put_dev(vub300->udev);
37862306a36Sopenharmony_ci	mmc_free_host(mmc);
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * and hence also frees vub300
38162306a36Sopenharmony_ci	 * which is contained at the end of struct mmc
38262306a36Sopenharmony_ci	 */
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	kref_get(&vub300->kref);
38862306a36Sopenharmony_ci	if (queue_work(cmndworkqueue, &vub300->cmndwork)) {
38962306a36Sopenharmony_ci		/*
39062306a36Sopenharmony_ci		 * then the cmndworkqueue was not previously
39162306a36Sopenharmony_ci		 * running and the above get ref is obvious
39262306a36Sopenharmony_ci		 * required and will be put when the thread
39362306a36Sopenharmony_ci		 * terminates by a specific call
39462306a36Sopenharmony_ci		 */
39562306a36Sopenharmony_ci	} else {
39662306a36Sopenharmony_ci		/*
39762306a36Sopenharmony_ci		 * the cmndworkqueue was already running from
39862306a36Sopenharmony_ci		 * a previous invocation and thus to keep the
39962306a36Sopenharmony_ci		 * kref counts correct we must undo the get
40062306a36Sopenharmony_ci		 */
40162306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	kref_get(&vub300->kref);
40862306a36Sopenharmony_ci	if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) {
40962306a36Sopenharmony_ci		/*
41062306a36Sopenharmony_ci		 * then the pollworkqueue was not previously
41162306a36Sopenharmony_ci		 * running and the above get ref is obvious
41262306a36Sopenharmony_ci		 * required and will be put when the thread
41362306a36Sopenharmony_ci		 * terminates by a specific call
41462306a36Sopenharmony_ci		 */
41562306a36Sopenharmony_ci	} else {
41662306a36Sopenharmony_ci		/*
41762306a36Sopenharmony_ci		 * the pollworkqueue was already running from
41862306a36Sopenharmony_ci		 * a previous invocation and thus to keep the
41962306a36Sopenharmony_ci		 * kref counts correct we must undo the get
42062306a36Sopenharmony_ci		 */
42162306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void vub300_queue_dead_work(struct vub300_mmc_host *vub300)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	kref_get(&vub300->kref);
42862306a36Sopenharmony_ci	if (queue_work(deadworkqueue, &vub300->deadwork)) {
42962306a36Sopenharmony_ci		/*
43062306a36Sopenharmony_ci		 * then the deadworkqueue was not previously
43162306a36Sopenharmony_ci		 * running and the above get ref is obvious
43262306a36Sopenharmony_ci		 * required and will be put when the thread
43362306a36Sopenharmony_ci		 * terminates by a specific call
43462306a36Sopenharmony_ci		 */
43562306a36Sopenharmony_ci	} else {
43662306a36Sopenharmony_ci		/*
43762306a36Sopenharmony_ci		 * the deadworkqueue was already running from
43862306a36Sopenharmony_ci		 * a previous invocation and thus to keep the
43962306a36Sopenharmony_ci		 * kref counts correct we must undo the get
44062306a36Sopenharmony_ci		 */
44162306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void irqpoll_res_completed(struct urb *urb)
44662306a36Sopenharmony_ci{				/* urb completion handler - hardirq */
44762306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
44862306a36Sopenharmony_ci	if (urb->status)
44962306a36Sopenharmony_ci		vub300->usb_transport_fail = urb->status;
45062306a36Sopenharmony_ci	complete(&vub300->irqpoll_complete);
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic void irqpoll_out_completed(struct urb *urb)
45462306a36Sopenharmony_ci{				/* urb completion handler - hardirq */
45562306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
45662306a36Sopenharmony_ci	if (urb->status) {
45762306a36Sopenharmony_ci		vub300->usb_transport_fail = urb->status;
45862306a36Sopenharmony_ci		complete(&vub300->irqpoll_complete);
45962306a36Sopenharmony_ci		return;
46062306a36Sopenharmony_ci	} else {
46162306a36Sopenharmony_ci		int ret;
46262306a36Sopenharmony_ci		unsigned int pipe =
46362306a36Sopenharmony_ci			usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
46462306a36Sopenharmony_ci		usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
46562306a36Sopenharmony_ci				  &vub300->resp, sizeof(vub300->resp),
46662306a36Sopenharmony_ci				  irqpoll_res_completed, vub300);
46762306a36Sopenharmony_ci		vub300->command_res_urb->actual_length = 0;
46862306a36Sopenharmony_ci		ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
46962306a36Sopenharmony_ci		if (ret) {
47062306a36Sopenharmony_ci			vub300->usb_transport_fail = ret;
47162306a36Sopenharmony_ci			complete(&vub300->irqpoll_complete);
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci		return;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic void send_irqpoll(struct vub300_mmc_host *vub300)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_pollwork_thread */
48062306a36Sopenharmony_ci	int retval;
48162306a36Sopenharmony_ci	int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout);
48262306a36Sopenharmony_ci	vub300->cmnd.poll.header_size = 22;
48362306a36Sopenharmony_ci	vub300->cmnd.poll.header_type = 1;
48462306a36Sopenharmony_ci	vub300->cmnd.poll.port_number = 0;
48562306a36Sopenharmony_ci	vub300->cmnd.poll.command_type = 2;
48662306a36Sopenharmony_ci	vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout;
48762306a36Sopenharmony_ci	vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8);
48862306a36Sopenharmony_ci	usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
48962306a36Sopenharmony_ci			  usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep)
49062306a36Sopenharmony_ci			  , &vub300->cmnd, sizeof(vub300->cmnd)
49162306a36Sopenharmony_ci			  , irqpoll_out_completed, vub300);
49262306a36Sopenharmony_ci	retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
49362306a36Sopenharmony_ci	if (0 > retval) {
49462306a36Sopenharmony_ci		vub300->usb_transport_fail = retval;
49562306a36Sopenharmony_ci		vub300_queue_poll_work(vub300, 1);
49662306a36Sopenharmony_ci		complete(&vub300->irqpoll_complete);
49762306a36Sopenharmony_ci		return;
49862306a36Sopenharmony_ci	} else {
49962306a36Sopenharmony_ci		return;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic void new_system_port_status(struct vub300_mmc_host *vub300)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	int old_card_present = vub300->card_present;
50662306a36Sopenharmony_ci	int new_card_present =
50762306a36Sopenharmony_ci		(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
50862306a36Sopenharmony_ci	vub300->read_only =
50962306a36Sopenharmony_ci		(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
51062306a36Sopenharmony_ci	if (new_card_present && !old_card_present) {
51162306a36Sopenharmony_ci		dev_info(&vub300->udev->dev, "card just inserted\n");
51262306a36Sopenharmony_ci		vub300->card_present = 1;
51362306a36Sopenharmony_ci		vub300->bus_width = 0;
51462306a36Sopenharmony_ci		if (disable_offload_processing)
51562306a36Sopenharmony_ci			strncpy(vub300->vub_name, "EMPTY Processing Disabled",
51662306a36Sopenharmony_ci				sizeof(vub300->vub_name));
51762306a36Sopenharmony_ci		else
51862306a36Sopenharmony_ci			vub300->vub_name[0] = 0;
51962306a36Sopenharmony_ci		mmc_detect_change(vub300->mmc, 1);
52062306a36Sopenharmony_ci	} else if (!new_card_present && old_card_present) {
52162306a36Sopenharmony_ci		dev_info(&vub300->udev->dev, "card just ejected\n");
52262306a36Sopenharmony_ci		vub300->card_present = 0;
52362306a36Sopenharmony_ci		mmc_detect_change(vub300->mmc, 0);
52462306a36Sopenharmony_ci	} else {
52562306a36Sopenharmony_ci		/* no change */
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300,
53062306a36Sopenharmony_ci					struct offload_registers_access
53162306a36Sopenharmony_ci					*register_access, u8 func)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count;
53462306a36Sopenharmony_ci	memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access,
53562306a36Sopenharmony_ci	       sizeof(struct offload_registers_access));
53662306a36Sopenharmony_ci	vub300->fn[func].offload_count += 1;
53762306a36Sopenharmony_ci	vub300->total_offload_count += 1;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void add_offloaded_reg(struct vub300_mmc_host *vub300,
54162306a36Sopenharmony_ci			      struct offload_registers_access *register_access)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	u32 Register = ((0x03 & register_access->command_byte[0]) << 15)
54462306a36Sopenharmony_ci			| ((0xFF & register_access->command_byte[1]) << 7)
54562306a36Sopenharmony_ci			| ((0xFE & register_access->command_byte[2]) >> 1);
54662306a36Sopenharmony_ci	u8 func = ((0x70 & register_access->command_byte[0]) >> 4);
54762306a36Sopenharmony_ci	u8 regs = vub300->dynamic_register_count;
54862306a36Sopenharmony_ci	u8 i = 0;
54962306a36Sopenharmony_ci	while (0 < regs-- && 1 == vub300->sdio_register[i].activate) {
55062306a36Sopenharmony_ci		if (vub300->sdio_register[i].func_num == func &&
55162306a36Sopenharmony_ci		    vub300->sdio_register[i].sdio_reg == Register) {
55262306a36Sopenharmony_ci			if (vub300->sdio_register[i].prepared == 0)
55362306a36Sopenharmony_ci				vub300->sdio_register[i].prepared = 1;
55462306a36Sopenharmony_ci			vub300->sdio_register[i].response =
55562306a36Sopenharmony_ci				register_access->Respond_Byte[2];
55662306a36Sopenharmony_ci			vub300->sdio_register[i].regvalue =
55762306a36Sopenharmony_ci				register_access->Respond_Byte[3];
55862306a36Sopenharmony_ci			return;
55962306a36Sopenharmony_ci		} else {
56062306a36Sopenharmony_ci			i += 1;
56162306a36Sopenharmony_ci			continue;
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci	__add_offloaded_reg_to_fifo(vub300, register_access, func);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic void check_vub300_port_status(struct vub300_mmc_host *vub300)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	/*
57062306a36Sopenharmony_ci	 * cmd_mutex is held by vub300_pollwork_thread,
57162306a36Sopenharmony_ci	 * vub300_deadwork_thread or vub300_cmndwork_thread
57262306a36Sopenharmony_ci	 */
57362306a36Sopenharmony_ci	int retval;
57462306a36Sopenharmony_ci	retval =
57562306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
57662306a36Sopenharmony_ci				GET_SYSTEM_PORT_STATUS,
57762306a36Sopenharmony_ci				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
57862306a36Sopenharmony_ci				0x0000, 0x0000, &vub300->system_port_status,
57962306a36Sopenharmony_ci				sizeof(vub300->system_port_status), 1000);
58062306a36Sopenharmony_ci	if (sizeof(vub300->system_port_status) == retval)
58162306a36Sopenharmony_ci		new_system_port_status(vub300);
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_pollwork_thread */
58762306a36Sopenharmony_ci	if (vub300->command_res_urb->actual_length == 0)
58862306a36Sopenharmony_ci		return;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	switch (vub300->resp.common.header_type) {
59162306a36Sopenharmony_ci	case RESPONSE_INTERRUPT:
59262306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
59362306a36Sopenharmony_ci		if (vub300->irq_enabled)
59462306a36Sopenharmony_ci			mmc_signal_sdio_irq(vub300->mmc);
59562306a36Sopenharmony_ci		else
59662306a36Sopenharmony_ci			vub300->irqs_queued += 1;
59762306a36Sopenharmony_ci		vub300->irq_disabled = 1;
59862306a36Sopenharmony_ci		mutex_unlock(&vub300->irq_mutex);
59962306a36Sopenharmony_ci		break;
60062306a36Sopenharmony_ci	case RESPONSE_ERROR:
60162306a36Sopenharmony_ci		if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE)
60262306a36Sopenharmony_ci			check_vub300_port_status(vub300);
60362306a36Sopenharmony_ci		break;
60462306a36Sopenharmony_ci	case RESPONSE_STATUS:
60562306a36Sopenharmony_ci		vub300->system_port_status = vub300->resp.status;
60662306a36Sopenharmony_ci		new_system_port_status(vub300);
60762306a36Sopenharmony_ci		if (!vub300->card_present)
60862306a36Sopenharmony_ci			vub300_queue_poll_work(vub300, HZ / 5);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	case RESPONSE_IRQ_DISABLED:
61162306a36Sopenharmony_ci	{
61262306a36Sopenharmony_ci		int offloaded_data_length = vub300->resp.common.header_size - 3;
61362306a36Sopenharmony_ci		int register_count = offloaded_data_length >> 3;
61462306a36Sopenharmony_ci		int ri = 0;
61562306a36Sopenharmony_ci		while (register_count--) {
61662306a36Sopenharmony_ci			add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
61762306a36Sopenharmony_ci			ri += 1;
61862306a36Sopenharmony_ci		}
61962306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
62062306a36Sopenharmony_ci		if (vub300->irq_enabled)
62162306a36Sopenharmony_ci			mmc_signal_sdio_irq(vub300->mmc);
62262306a36Sopenharmony_ci		else
62362306a36Sopenharmony_ci			vub300->irqs_queued += 1;
62462306a36Sopenharmony_ci		vub300->irq_disabled = 1;
62562306a36Sopenharmony_ci		mutex_unlock(&vub300->irq_mutex);
62662306a36Sopenharmony_ci		break;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci	case RESPONSE_IRQ_ENABLED:
62962306a36Sopenharmony_ci	{
63062306a36Sopenharmony_ci		int offloaded_data_length = vub300->resp.common.header_size - 3;
63162306a36Sopenharmony_ci		int register_count = offloaded_data_length >> 3;
63262306a36Sopenharmony_ci		int ri = 0;
63362306a36Sopenharmony_ci		while (register_count--) {
63462306a36Sopenharmony_ci			add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
63562306a36Sopenharmony_ci			ri += 1;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
63862306a36Sopenharmony_ci		if (vub300->irq_enabled)
63962306a36Sopenharmony_ci			mmc_signal_sdio_irq(vub300->mmc);
64062306a36Sopenharmony_ci		else
64162306a36Sopenharmony_ci			vub300->irqs_queued += 1;
64262306a36Sopenharmony_ci		vub300->irq_disabled = 0;
64362306a36Sopenharmony_ci		mutex_unlock(&vub300->irq_mutex);
64462306a36Sopenharmony_ci		break;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	case RESPONSE_NO_INTERRUPT:
64762306a36Sopenharmony_ci		vub300_queue_poll_work(vub300, 1);
64862306a36Sopenharmony_ci		break;
64962306a36Sopenharmony_ci	default:
65062306a36Sopenharmony_ci		break;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic void __do_poll(struct vub300_mmc_host *vub300)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_pollwork_thread */
65762306a36Sopenharmony_ci	unsigned long commretval;
65862306a36Sopenharmony_ci	mod_timer(&vub300->inactivity_timer, jiffies + HZ);
65962306a36Sopenharmony_ci	init_completion(&vub300->irqpoll_complete);
66062306a36Sopenharmony_ci	send_irqpoll(vub300);
66162306a36Sopenharmony_ci	commretval = wait_for_completion_timeout(&vub300->irqpoll_complete,
66262306a36Sopenharmony_ci						 msecs_to_jiffies(500));
66362306a36Sopenharmony_ci	if (vub300->usb_transport_fail) {
66462306a36Sopenharmony_ci		/* no need to do anything */
66562306a36Sopenharmony_ci	} else if (commretval == 0) {
66662306a36Sopenharmony_ci		vub300->usb_timed_out = 1;
66762306a36Sopenharmony_ci		usb_kill_urb(vub300->command_out_urb);
66862306a36Sopenharmony_ci		usb_kill_urb(vub300->command_res_urb);
66962306a36Sopenharmony_ci	} else { /* commretval > 0 */
67062306a36Sopenharmony_ci		__vub300_irqpoll_response(vub300);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/* this thread runs only when the driver
67562306a36Sopenharmony_ci * is trying to poll the device for an IRQ
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistatic void vub300_pollwork_thread(struct work_struct *work)
67862306a36Sopenharmony_ci{				/* NOT irq */
67962306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = container_of(work,
68062306a36Sopenharmony_ci			      struct vub300_mmc_host, pollwork.work);
68162306a36Sopenharmony_ci	if (!vub300->interface) {
68262306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
68362306a36Sopenharmony_ci		return;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci	mutex_lock(&vub300->cmd_mutex);
68662306a36Sopenharmony_ci	if (vub300->cmd) {
68762306a36Sopenharmony_ci		vub300_queue_poll_work(vub300, 1);
68862306a36Sopenharmony_ci	} else if (!vub300->card_present) {
68962306a36Sopenharmony_ci		/* no need to do anything */
69062306a36Sopenharmony_ci	} else { /* vub300->card_present */
69162306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
69262306a36Sopenharmony_ci		if (!vub300->irq_enabled) {
69362306a36Sopenharmony_ci			mutex_unlock(&vub300->irq_mutex);
69462306a36Sopenharmony_ci		} else if (vub300->irqs_queued) {
69562306a36Sopenharmony_ci			vub300->irqs_queued -= 1;
69662306a36Sopenharmony_ci			mmc_signal_sdio_irq(vub300->mmc);
69762306a36Sopenharmony_ci			mod_timer(&vub300->inactivity_timer, jiffies + HZ);
69862306a36Sopenharmony_ci			mutex_unlock(&vub300->irq_mutex);
69962306a36Sopenharmony_ci		} else { /* NOT vub300->irqs_queued */
70062306a36Sopenharmony_ci			mutex_unlock(&vub300->irq_mutex);
70162306a36Sopenharmony_ci			__do_poll(vub300);
70262306a36Sopenharmony_ci		}
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci	mutex_unlock(&vub300->cmd_mutex);
70562306a36Sopenharmony_ci	kref_put(&vub300->kref, vub300_delete);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic void vub300_deadwork_thread(struct work_struct *work)
70962306a36Sopenharmony_ci{				/* NOT irq */
71062306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 =
71162306a36Sopenharmony_ci		container_of(work, struct vub300_mmc_host, deadwork);
71262306a36Sopenharmony_ci	if (!vub300->interface) {
71362306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
71462306a36Sopenharmony_ci		return;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci	mutex_lock(&vub300->cmd_mutex);
71762306a36Sopenharmony_ci	if (vub300->cmd) {
71862306a36Sopenharmony_ci		/*
71962306a36Sopenharmony_ci		 * a command got in as the inactivity
72062306a36Sopenharmony_ci		 * timer expired - so we just let the
72162306a36Sopenharmony_ci		 * processing of the command show if
72262306a36Sopenharmony_ci		 * the device is dead
72362306a36Sopenharmony_ci		 */
72462306a36Sopenharmony_ci	} else if (vub300->card_present) {
72562306a36Sopenharmony_ci		check_vub300_port_status(vub300);
72662306a36Sopenharmony_ci	} else if (vub300->mmc && vub300->mmc->card) {
72762306a36Sopenharmony_ci		/*
72862306a36Sopenharmony_ci		 * the MMC core must not have responded
72962306a36Sopenharmony_ci		 * to the previous indication - lets
73062306a36Sopenharmony_ci		 * hope that it eventually does so we
73162306a36Sopenharmony_ci		 * will just ignore this for now
73262306a36Sopenharmony_ci		 */
73362306a36Sopenharmony_ci	} else {
73462306a36Sopenharmony_ci		check_vub300_port_status(vub300);
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci	mod_timer(&vub300->inactivity_timer, jiffies + HZ);
73762306a36Sopenharmony_ci	mutex_unlock(&vub300->cmd_mutex);
73862306a36Sopenharmony_ci	kref_put(&vub300->kref, vub300_delete);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic void vub300_inactivity_timer_expired(struct timer_list *t)
74262306a36Sopenharmony_ci{				/* softirq */
74362306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = from_timer(vub300, t,
74462306a36Sopenharmony_ci						    inactivity_timer);
74562306a36Sopenharmony_ci	if (!vub300->interface) {
74662306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
74762306a36Sopenharmony_ci	} else if (vub300->cmd) {
74862306a36Sopenharmony_ci		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
74962306a36Sopenharmony_ci	} else {
75062306a36Sopenharmony_ci		vub300_queue_dead_work(vub300);
75162306a36Sopenharmony_ci		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic int vub300_response_error(u8 error_code)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	switch (error_code) {
75862306a36Sopenharmony_ci	case SD_ERROR_PIO_TIMEOUT:
75962306a36Sopenharmony_ci	case SD_ERROR_1BIT_TIMEOUT:
76062306a36Sopenharmony_ci	case SD_ERROR_4BIT_TIMEOUT:
76162306a36Sopenharmony_ci		return -ETIMEDOUT;
76262306a36Sopenharmony_ci	case SD_ERROR_STAT_DATA:
76362306a36Sopenharmony_ci	case SD_ERROR_OVERRUN:
76462306a36Sopenharmony_ci	case SD_ERROR_STAT_CMD:
76562306a36Sopenharmony_ci	case SD_ERROR_STAT_CMD_TIMEOUT:
76662306a36Sopenharmony_ci	case SD_ERROR_SDCRDY_STUCK:
76762306a36Sopenharmony_ci	case SD_ERROR_UNHANDLED:
76862306a36Sopenharmony_ci	case SD_ERROR_1BIT_CRC_WRONG:
76962306a36Sopenharmony_ci	case SD_ERROR_4BIT_CRC_WRONG:
77062306a36Sopenharmony_ci	case SD_ERROR_1BIT_CRC_ERROR:
77162306a36Sopenharmony_ci	case SD_ERROR_4BIT_CRC_ERROR:
77262306a36Sopenharmony_ci	case SD_ERROR_NO_CMD_ENDBIT:
77362306a36Sopenharmony_ci	case SD_ERROR_NO_1BIT_DATEND:
77462306a36Sopenharmony_ci	case SD_ERROR_NO_4BIT_DATEND:
77562306a36Sopenharmony_ci	case SD_ERROR_1BIT_DATA_TIMEOUT:
77662306a36Sopenharmony_ci	case SD_ERROR_4BIT_DATA_TIMEOUT:
77762306a36Sopenharmony_ci	case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT:
77862306a36Sopenharmony_ci	case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT:
77962306a36Sopenharmony_ci		return -EILSEQ;
78062306a36Sopenharmony_ci	case 33:
78162306a36Sopenharmony_ci		return -EILSEQ;
78262306a36Sopenharmony_ci	case SD_ERROR_ILLEGAL_COMMAND:
78362306a36Sopenharmony_ci		return -EINVAL;
78462306a36Sopenharmony_ci	case SD_ERROR_NO_DEVICE:
78562306a36Sopenharmony_ci		return -ENOMEDIUM;
78662306a36Sopenharmony_ci	default:
78762306a36Sopenharmony_ci		return -ENODEV;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic void command_res_completed(struct urb *urb)
79262306a36Sopenharmony_ci{				/* urb completion handler - hardirq */
79362306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
79462306a36Sopenharmony_ci	if (urb->status) {
79562306a36Sopenharmony_ci		/* we have to let the initiator handle the error */
79662306a36Sopenharmony_ci	} else if (vub300->command_res_urb->actual_length == 0) {
79762306a36Sopenharmony_ci		/*
79862306a36Sopenharmony_ci		 * we have seen this happen once or twice and
79962306a36Sopenharmony_ci		 * we suspect a buggy USB host controller
80062306a36Sopenharmony_ci		 */
80162306a36Sopenharmony_ci	} else if (!vub300->data) {
80262306a36Sopenharmony_ci		/* this means that the command (typically CMD52) succeeded */
80362306a36Sopenharmony_ci	} else if (vub300->resp.common.header_type != 0x02) {
80462306a36Sopenharmony_ci		/*
80562306a36Sopenharmony_ci		 * this is an error response from the VUB300 chip
80662306a36Sopenharmony_ci		 * and we let the initiator handle it
80762306a36Sopenharmony_ci		 */
80862306a36Sopenharmony_ci	} else if (vub300->urb) {
80962306a36Sopenharmony_ci		vub300->cmd->error =
81062306a36Sopenharmony_ci			vub300_response_error(vub300->resp.error.error_code);
81162306a36Sopenharmony_ci		usb_unlink_urb(vub300->urb);
81262306a36Sopenharmony_ci	} else {
81362306a36Sopenharmony_ci		vub300->cmd->error =
81462306a36Sopenharmony_ci			vub300_response_error(vub300->resp.error.error_code);
81562306a36Sopenharmony_ci		usb_sg_cancel(&vub300->sg_request);
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci	complete(&vub300->command_complete);	/* got_response_in */
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic void command_out_completed(struct urb *urb)
82162306a36Sopenharmony_ci{				/* urb completion handler - hardirq */
82262306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
82362306a36Sopenharmony_ci	if (urb->status) {
82462306a36Sopenharmony_ci		complete(&vub300->command_complete);
82562306a36Sopenharmony_ci	} else {
82662306a36Sopenharmony_ci		int ret;
82762306a36Sopenharmony_ci		unsigned int pipe =
82862306a36Sopenharmony_ci			usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
82962306a36Sopenharmony_ci		usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
83062306a36Sopenharmony_ci				  &vub300->resp, sizeof(vub300->resp),
83162306a36Sopenharmony_ci				  command_res_completed, vub300);
83262306a36Sopenharmony_ci		vub300->command_res_urb->actual_length = 0;
83362306a36Sopenharmony_ci		ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
83462306a36Sopenharmony_ci		if (ret == 0) {
83562306a36Sopenharmony_ci			/*
83662306a36Sopenharmony_ci			 * the urb completion handler will call
83762306a36Sopenharmony_ci			 * our completion handler
83862306a36Sopenharmony_ci			 */
83962306a36Sopenharmony_ci		} else {
84062306a36Sopenharmony_ci			/*
84162306a36Sopenharmony_ci			 * and thus we only call it directly
84262306a36Sopenharmony_ci			 * when it will not be called
84362306a36Sopenharmony_ci			 */
84462306a36Sopenharmony_ci			complete(&vub300->command_complete);
84562306a36Sopenharmony_ci		}
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci/*
85062306a36Sopenharmony_ci * the STUFF bits are masked out for the comparisons
85162306a36Sopenharmony_ci */
85262306a36Sopenharmony_cistatic void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300,
85362306a36Sopenharmony_ci					   u32 cmd_arg)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	if ((0xFBFFFE00 & cmd_arg) == 0x80022200)
85662306a36Sopenharmony_ci		vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]);
85762306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80022000)
85862306a36Sopenharmony_ci		vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]);
85962306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80042200)
86062306a36Sopenharmony_ci		vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]);
86162306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80042000)
86262306a36Sopenharmony_ci		vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]);
86362306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80062200)
86462306a36Sopenharmony_ci		vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]);
86562306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80062000)
86662306a36Sopenharmony_ci		vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]);
86762306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80082200)
86862306a36Sopenharmony_ci		vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]);
86962306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x80082000)
87062306a36Sopenharmony_ci		vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]);
87162306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200)
87262306a36Sopenharmony_ci		vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]);
87362306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000)
87462306a36Sopenharmony_ci		vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]);
87562306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200)
87662306a36Sopenharmony_ci		vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]);
87762306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000)
87862306a36Sopenharmony_ci		vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]);
87962306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200)
88062306a36Sopenharmony_ci		vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]);
88162306a36Sopenharmony_ci	else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000)
88262306a36Sopenharmony_ci		vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]);
88362306a36Sopenharmony_ci	else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00)
88462306a36Sopenharmony_ci		vub300->bus_width = 1;
88562306a36Sopenharmony_ci	else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02)
88662306a36Sopenharmony_ci		vub300->bus_width = 4;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic void send_command(struct vub300_mmc_host *vub300)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_cmndwork_thread */
89262306a36Sopenharmony_ci	struct mmc_command *cmd = vub300->cmd;
89362306a36Sopenharmony_ci	struct mmc_data *data = vub300->data;
89462306a36Sopenharmony_ci	int retval;
89562306a36Sopenharmony_ci	int i;
89662306a36Sopenharmony_ci	u8 response_type;
89762306a36Sopenharmony_ci	if (vub300->app_spec) {
89862306a36Sopenharmony_ci		switch (cmd->opcode) {
89962306a36Sopenharmony_ci		case 6:
90062306a36Sopenharmony_ci			response_type = SDRT_1;
90162306a36Sopenharmony_ci			vub300->resp_len = 6;
90262306a36Sopenharmony_ci			if (0x00000000 == (0x00000003 & cmd->arg))
90362306a36Sopenharmony_ci				vub300->bus_width = 1;
90462306a36Sopenharmony_ci			else if (0x00000002 == (0x00000003 & cmd->arg))
90562306a36Sopenharmony_ci				vub300->bus_width = 4;
90662306a36Sopenharmony_ci			else
90762306a36Sopenharmony_ci				dev_err(&vub300->udev->dev,
90862306a36Sopenharmony_ci					"unexpected ACMD6 bus_width=%d\n",
90962306a36Sopenharmony_ci					0x00000003 & cmd->arg);
91062306a36Sopenharmony_ci			break;
91162306a36Sopenharmony_ci		case 13:
91262306a36Sopenharmony_ci			response_type = SDRT_1;
91362306a36Sopenharmony_ci			vub300->resp_len = 6;
91462306a36Sopenharmony_ci			break;
91562306a36Sopenharmony_ci		case 22:
91662306a36Sopenharmony_ci			response_type = SDRT_1;
91762306a36Sopenharmony_ci			vub300->resp_len = 6;
91862306a36Sopenharmony_ci			break;
91962306a36Sopenharmony_ci		case 23:
92062306a36Sopenharmony_ci			response_type = SDRT_1;
92162306a36Sopenharmony_ci			vub300->resp_len = 6;
92262306a36Sopenharmony_ci			break;
92362306a36Sopenharmony_ci		case 41:
92462306a36Sopenharmony_ci			response_type = SDRT_3;
92562306a36Sopenharmony_ci			vub300->resp_len = 6;
92662306a36Sopenharmony_ci			break;
92762306a36Sopenharmony_ci		case 42:
92862306a36Sopenharmony_ci			response_type = SDRT_1;
92962306a36Sopenharmony_ci			vub300->resp_len = 6;
93062306a36Sopenharmony_ci			break;
93162306a36Sopenharmony_ci		case 51:
93262306a36Sopenharmony_ci			response_type = SDRT_1;
93362306a36Sopenharmony_ci			vub300->resp_len = 6;
93462306a36Sopenharmony_ci			break;
93562306a36Sopenharmony_ci		case 55:
93662306a36Sopenharmony_ci			response_type = SDRT_1;
93762306a36Sopenharmony_ci			vub300->resp_len = 6;
93862306a36Sopenharmony_ci			break;
93962306a36Sopenharmony_ci		default:
94062306a36Sopenharmony_ci			vub300->resp_len = 0;
94162306a36Sopenharmony_ci			cmd->error = -EINVAL;
94262306a36Sopenharmony_ci			complete(&vub300->command_complete);
94362306a36Sopenharmony_ci			return;
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci		vub300->app_spec = 0;
94662306a36Sopenharmony_ci	} else {
94762306a36Sopenharmony_ci		switch (cmd->opcode) {
94862306a36Sopenharmony_ci		case 0:
94962306a36Sopenharmony_ci			response_type = SDRT_NONE;
95062306a36Sopenharmony_ci			vub300->resp_len = 0;
95162306a36Sopenharmony_ci			break;
95262306a36Sopenharmony_ci		case 1:
95362306a36Sopenharmony_ci			response_type = SDRT_3;
95462306a36Sopenharmony_ci			vub300->resp_len = 6;
95562306a36Sopenharmony_ci			break;
95662306a36Sopenharmony_ci		case 2:
95762306a36Sopenharmony_ci			response_type = SDRT_2;
95862306a36Sopenharmony_ci			vub300->resp_len = 17;
95962306a36Sopenharmony_ci			break;
96062306a36Sopenharmony_ci		case 3:
96162306a36Sopenharmony_ci			response_type = SDRT_6;
96262306a36Sopenharmony_ci			vub300->resp_len = 6;
96362306a36Sopenharmony_ci			break;
96462306a36Sopenharmony_ci		case 4:
96562306a36Sopenharmony_ci			response_type = SDRT_NONE;
96662306a36Sopenharmony_ci			vub300->resp_len = 0;
96762306a36Sopenharmony_ci			break;
96862306a36Sopenharmony_ci		case 5:
96962306a36Sopenharmony_ci			response_type = SDRT_4;
97062306a36Sopenharmony_ci			vub300->resp_len = 6;
97162306a36Sopenharmony_ci			break;
97262306a36Sopenharmony_ci		case 6:
97362306a36Sopenharmony_ci			response_type = SDRT_1;
97462306a36Sopenharmony_ci			vub300->resp_len = 6;
97562306a36Sopenharmony_ci			break;
97662306a36Sopenharmony_ci		case 7:
97762306a36Sopenharmony_ci			response_type = SDRT_1B;
97862306a36Sopenharmony_ci			vub300->resp_len = 6;
97962306a36Sopenharmony_ci			break;
98062306a36Sopenharmony_ci		case 8:
98162306a36Sopenharmony_ci			response_type = SDRT_7;
98262306a36Sopenharmony_ci			vub300->resp_len = 6;
98362306a36Sopenharmony_ci			break;
98462306a36Sopenharmony_ci		case 9:
98562306a36Sopenharmony_ci			response_type = SDRT_2;
98662306a36Sopenharmony_ci			vub300->resp_len = 17;
98762306a36Sopenharmony_ci			break;
98862306a36Sopenharmony_ci		case 10:
98962306a36Sopenharmony_ci			response_type = SDRT_2;
99062306a36Sopenharmony_ci			vub300->resp_len = 17;
99162306a36Sopenharmony_ci			break;
99262306a36Sopenharmony_ci		case 12:
99362306a36Sopenharmony_ci			response_type = SDRT_1B;
99462306a36Sopenharmony_ci			vub300->resp_len = 6;
99562306a36Sopenharmony_ci			break;
99662306a36Sopenharmony_ci		case 13:
99762306a36Sopenharmony_ci			response_type = SDRT_1;
99862306a36Sopenharmony_ci			vub300->resp_len = 6;
99962306a36Sopenharmony_ci			break;
100062306a36Sopenharmony_ci		case 15:
100162306a36Sopenharmony_ci			response_type = SDRT_NONE;
100262306a36Sopenharmony_ci			vub300->resp_len = 0;
100362306a36Sopenharmony_ci			break;
100462306a36Sopenharmony_ci		case 16:
100562306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
100662306a36Sopenharmony_ci				vub300->fbs[i] = 0xFFFF & cmd->arg;
100762306a36Sopenharmony_ci			response_type = SDRT_1;
100862306a36Sopenharmony_ci			vub300->resp_len = 6;
100962306a36Sopenharmony_ci			break;
101062306a36Sopenharmony_ci		case 17:
101162306a36Sopenharmony_ci		case 18:
101262306a36Sopenharmony_ci		case 24:
101362306a36Sopenharmony_ci		case 25:
101462306a36Sopenharmony_ci		case 27:
101562306a36Sopenharmony_ci			response_type = SDRT_1;
101662306a36Sopenharmony_ci			vub300->resp_len = 6;
101762306a36Sopenharmony_ci			break;
101862306a36Sopenharmony_ci		case 28:
101962306a36Sopenharmony_ci		case 29:
102062306a36Sopenharmony_ci			response_type = SDRT_1B;
102162306a36Sopenharmony_ci			vub300->resp_len = 6;
102262306a36Sopenharmony_ci			break;
102362306a36Sopenharmony_ci		case 30:
102462306a36Sopenharmony_ci		case 32:
102562306a36Sopenharmony_ci		case 33:
102662306a36Sopenharmony_ci			response_type = SDRT_1;
102762306a36Sopenharmony_ci			vub300->resp_len = 6;
102862306a36Sopenharmony_ci			break;
102962306a36Sopenharmony_ci		case 38:
103062306a36Sopenharmony_ci			response_type = SDRT_1B;
103162306a36Sopenharmony_ci			vub300->resp_len = 6;
103262306a36Sopenharmony_ci			break;
103362306a36Sopenharmony_ci		case 42:
103462306a36Sopenharmony_ci			response_type = SDRT_1;
103562306a36Sopenharmony_ci			vub300->resp_len = 6;
103662306a36Sopenharmony_ci			break;
103762306a36Sopenharmony_ci		case 52:
103862306a36Sopenharmony_ci			response_type = SDRT_5;
103962306a36Sopenharmony_ci			vub300->resp_len = 6;
104062306a36Sopenharmony_ci			snoop_block_size_and_bus_width(vub300, cmd->arg);
104162306a36Sopenharmony_ci			break;
104262306a36Sopenharmony_ci		case 53:
104362306a36Sopenharmony_ci			response_type = SDRT_5;
104462306a36Sopenharmony_ci			vub300->resp_len = 6;
104562306a36Sopenharmony_ci			break;
104662306a36Sopenharmony_ci		case 55:
104762306a36Sopenharmony_ci			response_type = SDRT_1;
104862306a36Sopenharmony_ci			vub300->resp_len = 6;
104962306a36Sopenharmony_ci			vub300->app_spec = 1;
105062306a36Sopenharmony_ci			break;
105162306a36Sopenharmony_ci		case 56:
105262306a36Sopenharmony_ci			response_type = SDRT_1;
105362306a36Sopenharmony_ci			vub300->resp_len = 6;
105462306a36Sopenharmony_ci			break;
105562306a36Sopenharmony_ci		default:
105662306a36Sopenharmony_ci			vub300->resp_len = 0;
105762306a36Sopenharmony_ci			cmd->error = -EINVAL;
105862306a36Sopenharmony_ci			complete(&vub300->command_complete);
105962306a36Sopenharmony_ci			return;
106062306a36Sopenharmony_ci		}
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci	/*
106362306a36Sopenharmony_ci	 * it is a shame that we can not use "sizeof(struct sd_command_header)"
106462306a36Sopenharmony_ci	 * this is because the packet _must_ be padded to 64 bytes
106562306a36Sopenharmony_ci	 */
106662306a36Sopenharmony_ci	vub300->cmnd.head.header_size = 20;
106762306a36Sopenharmony_ci	vub300->cmnd.head.header_type = 0x00;
106862306a36Sopenharmony_ci	vub300->cmnd.head.port_number = 0; /* "0" means port 1 */
106962306a36Sopenharmony_ci	vub300->cmnd.head.command_type = 0x00; /* standard read command */
107062306a36Sopenharmony_ci	vub300->cmnd.head.response_type = response_type;
107162306a36Sopenharmony_ci	vub300->cmnd.head.command_index = cmd->opcode;
107262306a36Sopenharmony_ci	vub300->cmnd.head.arguments[0] = cmd->arg >> 24;
107362306a36Sopenharmony_ci	vub300->cmnd.head.arguments[1] = cmd->arg >> 16;
107462306a36Sopenharmony_ci	vub300->cmnd.head.arguments[2] = cmd->arg >> 8;
107562306a36Sopenharmony_ci	vub300->cmnd.head.arguments[3] = cmd->arg >> 0;
107662306a36Sopenharmony_ci	if (cmd->opcode == 52) {
107762306a36Sopenharmony_ci		int fn = 0x7 & (cmd->arg >> 28);
107862306a36Sopenharmony_ci		vub300->cmnd.head.block_count[0] = 0;
107962306a36Sopenharmony_ci		vub300->cmnd.head.block_count[1] = 0;
108062306a36Sopenharmony_ci		vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF;
108162306a36Sopenharmony_ci		vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF;
108262306a36Sopenharmony_ci		vub300->cmnd.head.command_type = 0x00;
108362306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[0] = 0;
108462306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[1] = 0;
108562306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[2] = 0;
108662306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[3] = 0;
108762306a36Sopenharmony_ci	} else if (!data) {
108862306a36Sopenharmony_ci		vub300->cmnd.head.block_count[0] = 0;
108962306a36Sopenharmony_ci		vub300->cmnd.head.block_count[1] = 0;
109062306a36Sopenharmony_ci		vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF;
109162306a36Sopenharmony_ci		vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF;
109262306a36Sopenharmony_ci		vub300->cmnd.head.command_type = 0x00;
109362306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[0] = 0;
109462306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[1] = 0;
109562306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[2] = 0;
109662306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[3] = 0;
109762306a36Sopenharmony_ci	} else if (cmd->opcode == 53) {
109862306a36Sopenharmony_ci		int fn = 0x7 & (cmd->arg >> 28);
109962306a36Sopenharmony_ci		if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */
110062306a36Sopenharmony_ci			vub300->cmnd.head.block_count[0] =
110162306a36Sopenharmony_ci				(data->blocks >> 8) & 0xFF;
110262306a36Sopenharmony_ci			vub300->cmnd.head.block_count[1] =
110362306a36Sopenharmony_ci				(data->blocks >> 0) & 0xFF;
110462306a36Sopenharmony_ci			vub300->cmnd.head.block_size[0] =
110562306a36Sopenharmony_ci				(data->blksz >> 8) & 0xFF;
110662306a36Sopenharmony_ci			vub300->cmnd.head.block_size[1] =
110762306a36Sopenharmony_ci				(data->blksz >> 0) & 0xFF;
110862306a36Sopenharmony_ci		} else {	/* BYTE MODE */
110962306a36Sopenharmony_ci			vub300->cmnd.head.block_count[0] = 0;
111062306a36Sopenharmony_ci			vub300->cmnd.head.block_count[1] = 0;
111162306a36Sopenharmony_ci			vub300->cmnd.head.block_size[0] =
111262306a36Sopenharmony_ci				(vub300->datasize >> 8) & 0xFF;
111362306a36Sopenharmony_ci			vub300->cmnd.head.block_size[1] =
111462306a36Sopenharmony_ci				(vub300->datasize >> 0) & 0xFF;
111562306a36Sopenharmony_ci		}
111662306a36Sopenharmony_ci		vub300->cmnd.head.command_type =
111762306a36Sopenharmony_ci			(MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
111862306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[0] =
111962306a36Sopenharmony_ci			(vub300->datasize >> 24) & 0xFF;
112062306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[1] =
112162306a36Sopenharmony_ci			(vub300->datasize >> 16) & 0xFF;
112262306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[2] =
112362306a36Sopenharmony_ci			(vub300->datasize >> 8) & 0xFF;
112462306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[3] =
112562306a36Sopenharmony_ci			(vub300->datasize >> 0) & 0xFF;
112662306a36Sopenharmony_ci		if (vub300->datasize < vub300->fbs[fn]) {
112762306a36Sopenharmony_ci			vub300->cmnd.head.block_count[0] = 0;
112862306a36Sopenharmony_ci			vub300->cmnd.head.block_count[1] = 0;
112962306a36Sopenharmony_ci		}
113062306a36Sopenharmony_ci	} else {
113162306a36Sopenharmony_ci		vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF;
113262306a36Sopenharmony_ci		vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF;
113362306a36Sopenharmony_ci		vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF;
113462306a36Sopenharmony_ci		vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF;
113562306a36Sopenharmony_ci		vub300->cmnd.head.command_type =
113662306a36Sopenharmony_ci			(MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
113762306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[0] =
113862306a36Sopenharmony_ci			(vub300->datasize >> 24) & 0xFF;
113962306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[1] =
114062306a36Sopenharmony_ci			(vub300->datasize >> 16) & 0xFF;
114162306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[2] =
114262306a36Sopenharmony_ci			(vub300->datasize >> 8) & 0xFF;
114362306a36Sopenharmony_ci		vub300->cmnd.head.transfer_size[3] =
114462306a36Sopenharmony_ci			(vub300->datasize >> 0) & 0xFF;
114562306a36Sopenharmony_ci		if (vub300->datasize < vub300->fbs[0]) {
114662306a36Sopenharmony_ci			vub300->cmnd.head.block_count[0] = 0;
114762306a36Sopenharmony_ci			vub300->cmnd.head.block_count[1] = 0;
114862306a36Sopenharmony_ci		}
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci	if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) {
115162306a36Sopenharmony_ci		u16 block_size = vub300->cmnd.head.block_size[1] |
115262306a36Sopenharmony_ci			(vub300->cmnd.head.block_size[0] << 8);
115362306a36Sopenharmony_ci		u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY -
115462306a36Sopenharmony_ci			(FIRMWARE_BLOCK_BOUNDARY % block_size);
115562306a36Sopenharmony_ci		vub300->cmnd.head.block_boundary[0] =
115662306a36Sopenharmony_ci			(block_boundary >> 8) & 0xFF;
115762306a36Sopenharmony_ci		vub300->cmnd.head.block_boundary[1] =
115862306a36Sopenharmony_ci			(block_boundary >> 0) & 0xFF;
115962306a36Sopenharmony_ci	} else {
116062306a36Sopenharmony_ci		vub300->cmnd.head.block_boundary[0] = 0;
116162306a36Sopenharmony_ci		vub300->cmnd.head.block_boundary[1] = 0;
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci	usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
116462306a36Sopenharmony_ci			  usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep),
116562306a36Sopenharmony_ci			  &vub300->cmnd, sizeof(vub300->cmnd),
116662306a36Sopenharmony_ci			  command_out_completed, vub300);
116762306a36Sopenharmony_ci	retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
116862306a36Sopenharmony_ci	if (retval < 0) {
116962306a36Sopenharmony_ci		cmd->error = retval;
117062306a36Sopenharmony_ci		complete(&vub300->command_complete);
117162306a36Sopenharmony_ci		return;
117262306a36Sopenharmony_ci	} else {
117362306a36Sopenharmony_ci		return;
117462306a36Sopenharmony_ci	}
117562306a36Sopenharmony_ci}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci/*
117862306a36Sopenharmony_ci * timer callback runs in atomic mode
117962306a36Sopenharmony_ci *       so it cannot call usb_kill_urb()
118062306a36Sopenharmony_ci */
118162306a36Sopenharmony_cistatic void vub300_sg_timed_out(struct timer_list *t)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = from_timer(vub300, t,
118462306a36Sopenharmony_ci						    sg_transfer_timer);
118562306a36Sopenharmony_ci	vub300->usb_timed_out = 1;
118662306a36Sopenharmony_ci	usb_sg_cancel(&vub300->sg_request);
118762306a36Sopenharmony_ci	usb_unlink_urb(vub300->command_out_urb);
118862306a36Sopenharmony_ci	usb_unlink_urb(vub300->command_res_urb);
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic u16 roundup_to_multiple_of_64(u16 number)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	return 0xFFC0 & (0x3F + number);
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci/*
119762306a36Sopenharmony_ci * this is a separate function to solve the 80 column width restriction
119862306a36Sopenharmony_ci */
119962306a36Sopenharmony_cistatic void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
120062306a36Sopenharmony_ci					  const struct firmware *fw)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	u8 register_count = 0;
120362306a36Sopenharmony_ci	u16 ts = 0;
120462306a36Sopenharmony_ci	u16 interrupt_size = 0;
120562306a36Sopenharmony_ci	const u8 *data = fw->data;
120662306a36Sopenharmony_ci	int size = fw->size;
120762306a36Sopenharmony_ci	u8 c;
120862306a36Sopenharmony_ci	dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n",
120962306a36Sopenharmony_ci		 vub300->vub_name);
121062306a36Sopenharmony_ci	do {
121162306a36Sopenharmony_ci		c = *data++;
121262306a36Sopenharmony_ci	} while (size-- && c); /* skip comment */
121362306a36Sopenharmony_ci	dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data,
121462306a36Sopenharmony_ci		 vub300->vub_name);
121562306a36Sopenharmony_ci	if (size < 4) {
121662306a36Sopenharmony_ci		dev_err(&vub300->udev->dev,
121762306a36Sopenharmony_ci			"corrupt offload pseudocode in firmware %s\n",
121862306a36Sopenharmony_ci			vub300->vub_name);
121962306a36Sopenharmony_ci		strncpy(vub300->vub_name, "corrupt offload pseudocode",
122062306a36Sopenharmony_ci			sizeof(vub300->vub_name));
122162306a36Sopenharmony_ci		return;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci	interrupt_size += *data++;
122462306a36Sopenharmony_ci	size -= 1;
122562306a36Sopenharmony_ci	interrupt_size <<= 8;
122662306a36Sopenharmony_ci	interrupt_size += *data++;
122762306a36Sopenharmony_ci	size -= 1;
122862306a36Sopenharmony_ci	if (interrupt_size < size) {
122962306a36Sopenharmony_ci		u16 xfer_length = roundup_to_multiple_of_64(interrupt_size);
123062306a36Sopenharmony_ci		u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
123162306a36Sopenharmony_ci		if (xfer_buffer) {
123262306a36Sopenharmony_ci			int retval;
123362306a36Sopenharmony_ci			memcpy(xfer_buffer, data, interrupt_size);
123462306a36Sopenharmony_ci			memset(xfer_buffer + interrupt_size, 0,
123562306a36Sopenharmony_ci			       xfer_length - interrupt_size);
123662306a36Sopenharmony_ci			size -= interrupt_size;
123762306a36Sopenharmony_ci			data += interrupt_size;
123862306a36Sopenharmony_ci			retval =
123962306a36Sopenharmony_ci				usb_control_msg(vub300->udev,
124062306a36Sopenharmony_ci						usb_sndctrlpipe(vub300->udev, 0),
124162306a36Sopenharmony_ci						SET_INTERRUPT_PSEUDOCODE,
124262306a36Sopenharmony_ci						USB_DIR_OUT | USB_TYPE_VENDOR |
124362306a36Sopenharmony_ci						USB_RECIP_DEVICE, 0x0000, 0x0000,
124462306a36Sopenharmony_ci						xfer_buffer, xfer_length, 1000);
124562306a36Sopenharmony_ci			kfree(xfer_buffer);
124662306a36Sopenharmony_ci			if (retval < 0)
124762306a36Sopenharmony_ci				goto copy_error_message;
124862306a36Sopenharmony_ci		} else {
124962306a36Sopenharmony_ci			dev_err(&vub300->udev->dev,
125062306a36Sopenharmony_ci				"not enough memory for xfer buffer to send"
125162306a36Sopenharmony_ci				" INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
125262306a36Sopenharmony_ci				vub300->vub_name);
125362306a36Sopenharmony_ci			strncpy(vub300->vub_name,
125462306a36Sopenharmony_ci				"SDIO interrupt pseudocode download failed",
125562306a36Sopenharmony_ci				sizeof(vub300->vub_name));
125662306a36Sopenharmony_ci			return;
125762306a36Sopenharmony_ci		}
125862306a36Sopenharmony_ci	} else {
125962306a36Sopenharmony_ci		dev_err(&vub300->udev->dev,
126062306a36Sopenharmony_ci			"corrupt interrupt pseudocode in firmware %s %s\n",
126162306a36Sopenharmony_ci			fw->data, vub300->vub_name);
126262306a36Sopenharmony_ci		strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
126362306a36Sopenharmony_ci			sizeof(vub300->vub_name));
126462306a36Sopenharmony_ci		return;
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci	ts += *data++;
126762306a36Sopenharmony_ci	size -= 1;
126862306a36Sopenharmony_ci	ts <<= 8;
126962306a36Sopenharmony_ci	ts += *data++;
127062306a36Sopenharmony_ci	size -= 1;
127162306a36Sopenharmony_ci	if (ts < size) {
127262306a36Sopenharmony_ci		u16 xfer_length = roundup_to_multiple_of_64(ts);
127362306a36Sopenharmony_ci		u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
127462306a36Sopenharmony_ci		if (xfer_buffer) {
127562306a36Sopenharmony_ci			int retval;
127662306a36Sopenharmony_ci			memcpy(xfer_buffer, data, ts);
127762306a36Sopenharmony_ci			memset(xfer_buffer + ts, 0,
127862306a36Sopenharmony_ci			       xfer_length - ts);
127962306a36Sopenharmony_ci			size -= ts;
128062306a36Sopenharmony_ci			data += ts;
128162306a36Sopenharmony_ci			retval =
128262306a36Sopenharmony_ci				usb_control_msg(vub300->udev,
128362306a36Sopenharmony_ci						usb_sndctrlpipe(vub300->udev, 0),
128462306a36Sopenharmony_ci						SET_TRANSFER_PSEUDOCODE,
128562306a36Sopenharmony_ci						USB_DIR_OUT | USB_TYPE_VENDOR |
128662306a36Sopenharmony_ci						USB_RECIP_DEVICE, 0x0000, 0x0000,
128762306a36Sopenharmony_ci						xfer_buffer, xfer_length, 1000);
128862306a36Sopenharmony_ci			kfree(xfer_buffer);
128962306a36Sopenharmony_ci			if (retval < 0)
129062306a36Sopenharmony_ci				goto copy_error_message;
129162306a36Sopenharmony_ci		} else {
129262306a36Sopenharmony_ci			dev_err(&vub300->udev->dev,
129362306a36Sopenharmony_ci				"not enough memory for xfer buffer to send"
129462306a36Sopenharmony_ci				" TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
129562306a36Sopenharmony_ci				vub300->vub_name);
129662306a36Sopenharmony_ci			strncpy(vub300->vub_name,
129762306a36Sopenharmony_ci				"SDIO transfer pseudocode download failed",
129862306a36Sopenharmony_ci				sizeof(vub300->vub_name));
129962306a36Sopenharmony_ci			return;
130062306a36Sopenharmony_ci		}
130162306a36Sopenharmony_ci	} else {
130262306a36Sopenharmony_ci		dev_err(&vub300->udev->dev,
130362306a36Sopenharmony_ci			"corrupt transfer pseudocode in firmware %s %s\n",
130462306a36Sopenharmony_ci			fw->data, vub300->vub_name);
130562306a36Sopenharmony_ci		strncpy(vub300->vub_name, "corrupt transfer pseudocode",
130662306a36Sopenharmony_ci			sizeof(vub300->vub_name));
130762306a36Sopenharmony_ci		return;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci	register_count += *data++;
131062306a36Sopenharmony_ci	size -= 1;
131162306a36Sopenharmony_ci	if (register_count * 4 == size) {
131262306a36Sopenharmony_ci		int I = vub300->dynamic_register_count = register_count;
131362306a36Sopenharmony_ci		int i = 0;
131462306a36Sopenharmony_ci		while (I--) {
131562306a36Sopenharmony_ci			unsigned int func_num = 0;
131662306a36Sopenharmony_ci			vub300->sdio_register[i].func_num = *data++;
131762306a36Sopenharmony_ci			size -= 1;
131862306a36Sopenharmony_ci			func_num += *data++;
131962306a36Sopenharmony_ci			size -= 1;
132062306a36Sopenharmony_ci			func_num <<= 8;
132162306a36Sopenharmony_ci			func_num += *data++;
132262306a36Sopenharmony_ci			size -= 1;
132362306a36Sopenharmony_ci			func_num <<= 8;
132462306a36Sopenharmony_ci			func_num += *data++;
132562306a36Sopenharmony_ci			size -= 1;
132662306a36Sopenharmony_ci			vub300->sdio_register[i].sdio_reg = func_num;
132762306a36Sopenharmony_ci			vub300->sdio_register[i].activate = 1;
132862306a36Sopenharmony_ci			vub300->sdio_register[i].prepared = 0;
132962306a36Sopenharmony_ci			i += 1;
133062306a36Sopenharmony_ci		}
133162306a36Sopenharmony_ci		dev_info(&vub300->udev->dev,
133262306a36Sopenharmony_ci			 "initialized %d dynamic pseudocode registers\n",
133362306a36Sopenharmony_ci			 vub300->dynamic_register_count);
133462306a36Sopenharmony_ci		return;
133562306a36Sopenharmony_ci	} else {
133662306a36Sopenharmony_ci		dev_err(&vub300->udev->dev,
133762306a36Sopenharmony_ci			"corrupt dynamic registers in firmware %s\n",
133862306a36Sopenharmony_ci			vub300->vub_name);
133962306a36Sopenharmony_ci		strncpy(vub300->vub_name, "corrupt dynamic registers",
134062306a36Sopenharmony_ci			sizeof(vub300->vub_name));
134162306a36Sopenharmony_ci		return;
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_cicopy_error_message:
134562306a36Sopenharmony_ci	strncpy(vub300->vub_name, "SDIO pseudocode download failed",
134662306a36Sopenharmony_ci		sizeof(vub300->vub_name));
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci/*
135062306a36Sopenharmony_ci * if the binary containing the EMPTY PseudoCode can not be found
135162306a36Sopenharmony_ci * vub300->vub_name is set anyway in order to prevent an automatic retry
135262306a36Sopenharmony_ci */
135362306a36Sopenharmony_cistatic void download_offload_pseudocode(struct vub300_mmc_host *vub300)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	struct mmc_card *card = vub300->mmc->card;
135662306a36Sopenharmony_ci	int sdio_funcs = card->sdio_funcs;
135762306a36Sopenharmony_ci	const struct firmware *fw = NULL;
135862306a36Sopenharmony_ci	int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name),
135962306a36Sopenharmony_ci			 "vub_%04X%04X", card->cis.vendor, card->cis.device);
136062306a36Sopenharmony_ci	int n = 0;
136162306a36Sopenharmony_ci	int retval;
136262306a36Sopenharmony_ci	for (n = 0; n < sdio_funcs; n++) {
136362306a36Sopenharmony_ci		struct sdio_func *sf = card->sdio_func[n];
136462306a36Sopenharmony_ci		l += scnprintf(vub300->vub_name + l,
136562306a36Sopenharmony_ci			      sizeof(vub300->vub_name) - l, "_%04X%04X",
136662306a36Sopenharmony_ci			      sf->vendor, sf->device);
136762306a36Sopenharmony_ci	}
136862306a36Sopenharmony_ci	snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
136962306a36Sopenharmony_ci	dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
137062306a36Sopenharmony_ci		 vub300->vub_name);
137162306a36Sopenharmony_ci	retval = request_firmware(&fw, vub300->vub_name, &card->dev);
137262306a36Sopenharmony_ci	if (retval < 0) {
137362306a36Sopenharmony_ci		strncpy(vub300->vub_name, "vub_default.bin",
137462306a36Sopenharmony_ci			sizeof(vub300->vub_name));
137562306a36Sopenharmony_ci		retval = request_firmware(&fw, vub300->vub_name, &card->dev);
137662306a36Sopenharmony_ci		if (retval < 0) {
137762306a36Sopenharmony_ci			strncpy(vub300->vub_name,
137862306a36Sopenharmony_ci				"no SDIO offload firmware found",
137962306a36Sopenharmony_ci				sizeof(vub300->vub_name));
138062306a36Sopenharmony_ci		} else {
138162306a36Sopenharmony_ci			__download_offload_pseudocode(vub300, fw);
138262306a36Sopenharmony_ci			release_firmware(fw);
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci	} else {
138562306a36Sopenharmony_ci		__download_offload_pseudocode(vub300, fw);
138662306a36Sopenharmony_ci		release_firmware(fw);
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void vub300_usb_bulk_msg_completion(struct urb *urb)
139162306a36Sopenharmony_ci{				/* urb completion handler - hardirq */
139262306a36Sopenharmony_ci	complete((struct completion *)urb->context);
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300,
139662306a36Sopenharmony_ci			       unsigned int pipe, void *data, int len,
139762306a36Sopenharmony_ci			       int *actual_length, int timeout_msecs)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_cmndwork_thread */
140062306a36Sopenharmony_ci	struct usb_device *usb_dev = vub300->udev;
140162306a36Sopenharmony_ci	struct completion done;
140262306a36Sopenharmony_ci	int retval;
140362306a36Sopenharmony_ci	vub300->urb = usb_alloc_urb(0, GFP_KERNEL);
140462306a36Sopenharmony_ci	if (!vub300->urb)
140562306a36Sopenharmony_ci		return -ENOMEM;
140662306a36Sopenharmony_ci	usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len,
140762306a36Sopenharmony_ci			  vub300_usb_bulk_msg_completion, NULL);
140862306a36Sopenharmony_ci	init_completion(&done);
140962306a36Sopenharmony_ci	vub300->urb->context = &done;
141062306a36Sopenharmony_ci	vub300->urb->actual_length = 0;
141162306a36Sopenharmony_ci	retval = usb_submit_urb(vub300->urb, GFP_KERNEL);
141262306a36Sopenharmony_ci	if (unlikely(retval))
141362306a36Sopenharmony_ci		goto out;
141462306a36Sopenharmony_ci	if (!wait_for_completion_timeout
141562306a36Sopenharmony_ci	    (&done, msecs_to_jiffies(timeout_msecs))) {
141662306a36Sopenharmony_ci		retval = -ETIMEDOUT;
141762306a36Sopenharmony_ci		usb_kill_urb(vub300->urb);
141862306a36Sopenharmony_ci	} else {
141962306a36Sopenharmony_ci		retval = vub300->urb->status;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ciout:
142262306a36Sopenharmony_ci	*actual_length = vub300->urb->actual_length;
142362306a36Sopenharmony_ci	usb_free_urb(vub300->urb);
142462306a36Sopenharmony_ci	vub300->urb = NULL;
142562306a36Sopenharmony_ci	return retval;
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int __command_read_data(struct vub300_mmc_host *vub300,
142962306a36Sopenharmony_ci			       struct mmc_command *cmd, struct mmc_data *data)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_cmndwork_thread */
143262306a36Sopenharmony_ci	int linear_length = vub300->datasize;
143362306a36Sopenharmony_ci	int padded_length = vub300->large_usb_packets ?
143462306a36Sopenharmony_ci		((511 + linear_length) >> 9) << 9 :
143562306a36Sopenharmony_ci		((63 + linear_length) >> 6) << 6;
143662306a36Sopenharmony_ci	if ((padded_length == linear_length) || !pad_input_to_usb_pkt) {
143762306a36Sopenharmony_ci		int result;
143862306a36Sopenharmony_ci		unsigned pipe;
143962306a36Sopenharmony_ci		pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep);
144062306a36Sopenharmony_ci		result = usb_sg_init(&vub300->sg_request, vub300->udev,
144162306a36Sopenharmony_ci				     pipe, 0, data->sg,
144262306a36Sopenharmony_ci				     data->sg_len, 0, GFP_KERNEL);
144362306a36Sopenharmony_ci		if (result < 0) {
144462306a36Sopenharmony_ci			usb_unlink_urb(vub300->command_out_urb);
144562306a36Sopenharmony_ci			usb_unlink_urb(vub300->command_res_urb);
144662306a36Sopenharmony_ci			cmd->error = result;
144762306a36Sopenharmony_ci			data->bytes_xfered = 0;
144862306a36Sopenharmony_ci			return 0;
144962306a36Sopenharmony_ci		} else {
145062306a36Sopenharmony_ci			vub300->sg_transfer_timer.expires =
145162306a36Sopenharmony_ci				jiffies + msecs_to_jiffies(2000 +
145262306a36Sopenharmony_ci						  (linear_length / 16384));
145362306a36Sopenharmony_ci			add_timer(&vub300->sg_transfer_timer);
145462306a36Sopenharmony_ci			usb_sg_wait(&vub300->sg_request);
145562306a36Sopenharmony_ci			del_timer(&vub300->sg_transfer_timer);
145662306a36Sopenharmony_ci			if (vub300->sg_request.status < 0) {
145762306a36Sopenharmony_ci				cmd->error = vub300->sg_request.status;
145862306a36Sopenharmony_ci				data->bytes_xfered = 0;
145962306a36Sopenharmony_ci				return 0;
146062306a36Sopenharmony_ci			} else {
146162306a36Sopenharmony_ci				data->bytes_xfered = vub300->datasize;
146262306a36Sopenharmony_ci				return linear_length;
146362306a36Sopenharmony_ci			}
146462306a36Sopenharmony_ci		}
146562306a36Sopenharmony_ci	} else {
146662306a36Sopenharmony_ci		u8 *buf = kmalloc(padded_length, GFP_KERNEL);
146762306a36Sopenharmony_ci		if (buf) {
146862306a36Sopenharmony_ci			int result;
146962306a36Sopenharmony_ci			unsigned pipe = usb_rcvbulkpipe(vub300->udev,
147062306a36Sopenharmony_ci							vub300->data_inp_ep);
147162306a36Sopenharmony_ci			int actual_length = 0;
147262306a36Sopenharmony_ci			result = vub300_usb_bulk_msg(vub300, pipe, buf,
147362306a36Sopenharmony_ci					     padded_length, &actual_length,
147462306a36Sopenharmony_ci					     2000 + (padded_length / 16384));
147562306a36Sopenharmony_ci			if (result < 0) {
147662306a36Sopenharmony_ci				cmd->error = result;
147762306a36Sopenharmony_ci				data->bytes_xfered = 0;
147862306a36Sopenharmony_ci				kfree(buf);
147962306a36Sopenharmony_ci				return 0;
148062306a36Sopenharmony_ci			} else if (actual_length < linear_length) {
148162306a36Sopenharmony_ci				cmd->error = -EREMOTEIO;
148262306a36Sopenharmony_ci				data->bytes_xfered = 0;
148362306a36Sopenharmony_ci				kfree(buf);
148462306a36Sopenharmony_ci				return 0;
148562306a36Sopenharmony_ci			} else {
148662306a36Sopenharmony_ci				sg_copy_from_buffer(data->sg, data->sg_len, buf,
148762306a36Sopenharmony_ci						    linear_length);
148862306a36Sopenharmony_ci				kfree(buf);
148962306a36Sopenharmony_ci				data->bytes_xfered = vub300->datasize;
149062306a36Sopenharmony_ci				return linear_length;
149162306a36Sopenharmony_ci			}
149262306a36Sopenharmony_ci		} else {
149362306a36Sopenharmony_ci			cmd->error = -ENOMEM;
149462306a36Sopenharmony_ci			data->bytes_xfered = 0;
149562306a36Sopenharmony_ci			return 0;
149662306a36Sopenharmony_ci		}
149762306a36Sopenharmony_ci	}
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic int __command_write_data(struct vub300_mmc_host *vub300,
150162306a36Sopenharmony_ci				struct mmc_command *cmd, struct mmc_data *data)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_cmndwork_thread */
150462306a36Sopenharmony_ci	unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep);
150562306a36Sopenharmony_ci	int linear_length = vub300->datasize;
150662306a36Sopenharmony_ci	int modulo_64_length = linear_length & 0x003F;
150762306a36Sopenharmony_ci	int modulo_512_length = linear_length & 0x01FF;
150862306a36Sopenharmony_ci	if (linear_length < 64) {
150962306a36Sopenharmony_ci		int result;
151062306a36Sopenharmony_ci		int actual_length;
151162306a36Sopenharmony_ci		sg_copy_to_buffer(data->sg, data->sg_len,
151262306a36Sopenharmony_ci				  vub300->padded_buffer,
151362306a36Sopenharmony_ci				  sizeof(vub300->padded_buffer));
151462306a36Sopenharmony_ci		memset(vub300->padded_buffer + linear_length, 0,
151562306a36Sopenharmony_ci		       sizeof(vub300->padded_buffer) - linear_length);
151662306a36Sopenharmony_ci		result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer,
151762306a36Sopenharmony_ci					     sizeof(vub300->padded_buffer),
151862306a36Sopenharmony_ci					     &actual_length, 2000 +
151962306a36Sopenharmony_ci					     (sizeof(vub300->padded_buffer) /
152062306a36Sopenharmony_ci					      16384));
152162306a36Sopenharmony_ci		if (result < 0) {
152262306a36Sopenharmony_ci			cmd->error = result;
152362306a36Sopenharmony_ci			data->bytes_xfered = 0;
152462306a36Sopenharmony_ci		} else {
152562306a36Sopenharmony_ci			data->bytes_xfered = vub300->datasize;
152662306a36Sopenharmony_ci		}
152762306a36Sopenharmony_ci	} else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) ||
152862306a36Sopenharmony_ci		    (vub300->large_usb_packets && (64 > modulo_512_length))
152962306a36Sopenharmony_ci		) {		/* don't you just love these work-rounds */
153062306a36Sopenharmony_ci		int padded_length = ((63 + linear_length) >> 6) << 6;
153162306a36Sopenharmony_ci		u8 *buf = kmalloc(padded_length, GFP_KERNEL);
153262306a36Sopenharmony_ci		if (buf) {
153362306a36Sopenharmony_ci			int result;
153462306a36Sopenharmony_ci			int actual_length;
153562306a36Sopenharmony_ci			sg_copy_to_buffer(data->sg, data->sg_len, buf,
153662306a36Sopenharmony_ci					  padded_length);
153762306a36Sopenharmony_ci			memset(buf + linear_length, 0,
153862306a36Sopenharmony_ci			       padded_length - linear_length);
153962306a36Sopenharmony_ci			result =
154062306a36Sopenharmony_ci				vub300_usb_bulk_msg(vub300, pipe, buf,
154162306a36Sopenharmony_ci						    padded_length, &actual_length,
154262306a36Sopenharmony_ci						    2000 + padded_length / 16384);
154362306a36Sopenharmony_ci			kfree(buf);
154462306a36Sopenharmony_ci			if (result < 0) {
154562306a36Sopenharmony_ci				cmd->error = result;
154662306a36Sopenharmony_ci				data->bytes_xfered = 0;
154762306a36Sopenharmony_ci			} else {
154862306a36Sopenharmony_ci				data->bytes_xfered = vub300->datasize;
154962306a36Sopenharmony_ci			}
155062306a36Sopenharmony_ci		} else {
155162306a36Sopenharmony_ci			cmd->error = -ENOMEM;
155262306a36Sopenharmony_ci			data->bytes_xfered = 0;
155362306a36Sopenharmony_ci		}
155462306a36Sopenharmony_ci	} else {		/* no data padding required */
155562306a36Sopenharmony_ci		int result;
155662306a36Sopenharmony_ci		unsigned char buf[64 * 4];
155762306a36Sopenharmony_ci		sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf));
155862306a36Sopenharmony_ci		result = usb_sg_init(&vub300->sg_request, vub300->udev,
155962306a36Sopenharmony_ci				     pipe, 0, data->sg,
156062306a36Sopenharmony_ci				     data->sg_len, 0, GFP_KERNEL);
156162306a36Sopenharmony_ci		if (result < 0) {
156262306a36Sopenharmony_ci			usb_unlink_urb(vub300->command_out_urb);
156362306a36Sopenharmony_ci			usb_unlink_urb(vub300->command_res_urb);
156462306a36Sopenharmony_ci			cmd->error = result;
156562306a36Sopenharmony_ci			data->bytes_xfered = 0;
156662306a36Sopenharmony_ci		} else {
156762306a36Sopenharmony_ci			vub300->sg_transfer_timer.expires =
156862306a36Sopenharmony_ci				jiffies + msecs_to_jiffies(2000 +
156962306a36Sopenharmony_ci							   linear_length / 16384);
157062306a36Sopenharmony_ci			add_timer(&vub300->sg_transfer_timer);
157162306a36Sopenharmony_ci			usb_sg_wait(&vub300->sg_request);
157262306a36Sopenharmony_ci			if (cmd->error) {
157362306a36Sopenharmony_ci				data->bytes_xfered = 0;
157462306a36Sopenharmony_ci			} else {
157562306a36Sopenharmony_ci				del_timer(&vub300->sg_transfer_timer);
157662306a36Sopenharmony_ci				if (vub300->sg_request.status < 0) {
157762306a36Sopenharmony_ci					cmd->error = vub300->sg_request.status;
157862306a36Sopenharmony_ci					data->bytes_xfered = 0;
157962306a36Sopenharmony_ci				} else {
158062306a36Sopenharmony_ci					data->bytes_xfered = vub300->datasize;
158162306a36Sopenharmony_ci				}
158262306a36Sopenharmony_ci			}
158362306a36Sopenharmony_ci		}
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci	return linear_length;
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic void __vub300_command_response(struct vub300_mmc_host *vub300,
158962306a36Sopenharmony_ci				      struct mmc_command *cmd,
159062306a36Sopenharmony_ci				      struct mmc_data *data, int data_length)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_cmndwork_thread */
159362306a36Sopenharmony_ci	long respretval;
159462306a36Sopenharmony_ci	int msec_timeout = 1000 + data_length / 4;
159562306a36Sopenharmony_ci	respretval =
159662306a36Sopenharmony_ci		wait_for_completion_timeout(&vub300->command_complete,
159762306a36Sopenharmony_ci					    msecs_to_jiffies(msec_timeout));
159862306a36Sopenharmony_ci	if (respretval == 0) { /* TIMED OUT */
159962306a36Sopenharmony_ci		/* we don't know which of "out" and "res" if any failed */
160062306a36Sopenharmony_ci		int result;
160162306a36Sopenharmony_ci		vub300->usb_timed_out = 1;
160262306a36Sopenharmony_ci		usb_kill_urb(vub300->command_out_urb);
160362306a36Sopenharmony_ci		usb_kill_urb(vub300->command_res_urb);
160462306a36Sopenharmony_ci		cmd->error = -ETIMEDOUT;
160562306a36Sopenharmony_ci		result = usb_lock_device_for_reset(vub300->udev,
160662306a36Sopenharmony_ci						   vub300->interface);
160762306a36Sopenharmony_ci		if (result == 0) {
160862306a36Sopenharmony_ci			result = usb_reset_device(vub300->udev);
160962306a36Sopenharmony_ci			usb_unlock_device(vub300->udev);
161062306a36Sopenharmony_ci		}
161162306a36Sopenharmony_ci	} else if (respretval < 0) {
161262306a36Sopenharmony_ci		/* we don't know which of "out" and "res" if any failed */
161362306a36Sopenharmony_ci		usb_kill_urb(vub300->command_out_urb);
161462306a36Sopenharmony_ci		usb_kill_urb(vub300->command_res_urb);
161562306a36Sopenharmony_ci		cmd->error = respretval;
161662306a36Sopenharmony_ci	} else if (cmd->error) {
161762306a36Sopenharmony_ci		/*
161862306a36Sopenharmony_ci		 * the error occurred sending the command
161962306a36Sopenharmony_ci		 * or receiving the response
162062306a36Sopenharmony_ci		 */
162162306a36Sopenharmony_ci	} else if (vub300->command_out_urb->status) {
162262306a36Sopenharmony_ci		vub300->usb_transport_fail = vub300->command_out_urb->status;
162362306a36Sopenharmony_ci		cmd->error = -EPROTO == vub300->command_out_urb->status ?
162462306a36Sopenharmony_ci			-ESHUTDOWN : vub300->command_out_urb->status;
162562306a36Sopenharmony_ci	} else if (vub300->command_res_urb->status) {
162662306a36Sopenharmony_ci		vub300->usb_transport_fail = vub300->command_res_urb->status;
162762306a36Sopenharmony_ci		cmd->error = -EPROTO == vub300->command_res_urb->status ?
162862306a36Sopenharmony_ci			-ESHUTDOWN : vub300->command_res_urb->status;
162962306a36Sopenharmony_ci	} else if (vub300->resp.common.header_type == 0x00) {
163062306a36Sopenharmony_ci		/*
163162306a36Sopenharmony_ci		 * the command completed successfully
163262306a36Sopenharmony_ci		 * and there was no piggybacked data
163362306a36Sopenharmony_ci		 */
163462306a36Sopenharmony_ci	} else if (vub300->resp.common.header_type == RESPONSE_ERROR) {
163562306a36Sopenharmony_ci		cmd->error =
163662306a36Sopenharmony_ci			vub300_response_error(vub300->resp.error.error_code);
163762306a36Sopenharmony_ci		if (vub300->data)
163862306a36Sopenharmony_ci			usb_sg_cancel(&vub300->sg_request);
163962306a36Sopenharmony_ci	} else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) {
164062306a36Sopenharmony_ci		int offloaded_data_length =
164162306a36Sopenharmony_ci			vub300->resp.common.header_size -
164262306a36Sopenharmony_ci			sizeof(struct sd_register_header);
164362306a36Sopenharmony_ci		int register_count = offloaded_data_length >> 3;
164462306a36Sopenharmony_ci		int ri = 0;
164562306a36Sopenharmony_ci		while (register_count--) {
164662306a36Sopenharmony_ci			add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
164762306a36Sopenharmony_ci			ri += 1;
164862306a36Sopenharmony_ci		}
164962306a36Sopenharmony_ci		vub300->resp.common.header_size =
165062306a36Sopenharmony_ci			sizeof(struct sd_register_header);
165162306a36Sopenharmony_ci		vub300->resp.common.header_type = 0x00;
165262306a36Sopenharmony_ci		cmd->error = 0;
165362306a36Sopenharmony_ci	} else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) {
165462306a36Sopenharmony_ci		int offloaded_data_length =
165562306a36Sopenharmony_ci			vub300->resp.common.header_size -
165662306a36Sopenharmony_ci			sizeof(struct sd_register_header);
165762306a36Sopenharmony_ci		int register_count = offloaded_data_length >> 3;
165862306a36Sopenharmony_ci		int ri = 0;
165962306a36Sopenharmony_ci		while (register_count--) {
166062306a36Sopenharmony_ci			add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
166162306a36Sopenharmony_ci			ri += 1;
166262306a36Sopenharmony_ci		}
166362306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
166462306a36Sopenharmony_ci		if (vub300->irqs_queued) {
166562306a36Sopenharmony_ci			vub300->irqs_queued += 1;
166662306a36Sopenharmony_ci		} else if (vub300->irq_enabled) {
166762306a36Sopenharmony_ci			vub300->irqs_queued += 1;
166862306a36Sopenharmony_ci			vub300_queue_poll_work(vub300, 0);
166962306a36Sopenharmony_ci		} else {
167062306a36Sopenharmony_ci			vub300->irqs_queued += 1;
167162306a36Sopenharmony_ci		}
167262306a36Sopenharmony_ci		vub300->irq_disabled = 1;
167362306a36Sopenharmony_ci		mutex_unlock(&vub300->irq_mutex);
167462306a36Sopenharmony_ci		vub300->resp.common.header_size =
167562306a36Sopenharmony_ci			sizeof(struct sd_register_header);
167662306a36Sopenharmony_ci		vub300->resp.common.header_type = 0x00;
167762306a36Sopenharmony_ci		cmd->error = 0;
167862306a36Sopenharmony_ci	} else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) {
167962306a36Sopenharmony_ci		int offloaded_data_length =
168062306a36Sopenharmony_ci			vub300->resp.common.header_size -
168162306a36Sopenharmony_ci			sizeof(struct sd_register_header);
168262306a36Sopenharmony_ci		int register_count = offloaded_data_length >> 3;
168362306a36Sopenharmony_ci		int ri = 0;
168462306a36Sopenharmony_ci		while (register_count--) {
168562306a36Sopenharmony_ci			add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
168662306a36Sopenharmony_ci			ri += 1;
168762306a36Sopenharmony_ci		}
168862306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
168962306a36Sopenharmony_ci		if (vub300->irqs_queued) {
169062306a36Sopenharmony_ci			vub300->irqs_queued += 1;
169162306a36Sopenharmony_ci		} else if (vub300->irq_enabled) {
169262306a36Sopenharmony_ci			vub300->irqs_queued += 1;
169362306a36Sopenharmony_ci			vub300_queue_poll_work(vub300, 0);
169462306a36Sopenharmony_ci		} else {
169562306a36Sopenharmony_ci			vub300->irqs_queued += 1;
169662306a36Sopenharmony_ci		}
169762306a36Sopenharmony_ci		vub300->irq_disabled = 0;
169862306a36Sopenharmony_ci		mutex_unlock(&vub300->irq_mutex);
169962306a36Sopenharmony_ci		vub300->resp.common.header_size =
170062306a36Sopenharmony_ci			sizeof(struct sd_register_header);
170162306a36Sopenharmony_ci		vub300->resp.common.header_type = 0x00;
170262306a36Sopenharmony_ci		cmd->error = 0;
170362306a36Sopenharmony_ci	} else {
170462306a36Sopenharmony_ci		cmd->error = -EINVAL;
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic void construct_request_response(struct vub300_mmc_host *vub300,
170962306a36Sopenharmony_ci				       struct mmc_command *cmd)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	int resp_len = vub300->resp_len;
171262306a36Sopenharmony_ci	int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1;
171362306a36Sopenharmony_ci	int bytes = 3 & less_cmd;
171462306a36Sopenharmony_ci	int words = less_cmd >> 2;
171562306a36Sopenharmony_ci	u8 *r = vub300->resp.response.command_response;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (!resp_len)
171862306a36Sopenharmony_ci		return;
171962306a36Sopenharmony_ci	if (bytes == 3) {
172062306a36Sopenharmony_ci		cmd->resp[words] = (r[1 + (words << 2)] << 24)
172162306a36Sopenharmony_ci			| (r[2 + (words << 2)] << 16)
172262306a36Sopenharmony_ci			| (r[3 + (words << 2)] << 8);
172362306a36Sopenharmony_ci	} else if (bytes == 2) {
172462306a36Sopenharmony_ci		cmd->resp[words] = (r[1 + (words << 2)] << 24)
172562306a36Sopenharmony_ci			| (r[2 + (words << 2)] << 16);
172662306a36Sopenharmony_ci	} else if (bytes == 1) {
172762306a36Sopenharmony_ci		cmd->resp[words] = (r[1 + (words << 2)] << 24);
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci	while (words-- > 0) {
173062306a36Sopenharmony_ci		cmd->resp[words] = (r[1 + (words << 2)] << 24)
173162306a36Sopenharmony_ci			| (r[2 + (words << 2)] << 16)
173262306a36Sopenharmony_ci			| (r[3 + (words << 2)] << 8)
173362306a36Sopenharmony_ci			| (r[4 + (words << 2)] << 0);
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci	if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0]))
173662306a36Sopenharmony_ci		cmd->resp[0] &= 0xFFFFFF00;
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci/* this thread runs only when there is an upper level command req outstanding */
174062306a36Sopenharmony_cistatic void vub300_cmndwork_thread(struct work_struct *work)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 =
174362306a36Sopenharmony_ci		container_of(work, struct vub300_mmc_host, cmndwork);
174462306a36Sopenharmony_ci	if (!vub300->interface) {
174562306a36Sopenharmony_ci		kref_put(&vub300->kref, vub300_delete);
174662306a36Sopenharmony_ci		return;
174762306a36Sopenharmony_ci	} else {
174862306a36Sopenharmony_ci		struct mmc_request *req = vub300->req;
174962306a36Sopenharmony_ci		struct mmc_command *cmd = vub300->cmd;
175062306a36Sopenharmony_ci		struct mmc_data *data = vub300->data;
175162306a36Sopenharmony_ci		int data_length;
175262306a36Sopenharmony_ci		mutex_lock(&vub300->cmd_mutex);
175362306a36Sopenharmony_ci		init_completion(&vub300->command_complete);
175462306a36Sopenharmony_ci		if (likely(vub300->vub_name[0]) || !vub300->mmc->card) {
175562306a36Sopenharmony_ci			/*
175662306a36Sopenharmony_ci			 * the name of the EMPTY Pseudo firmware file
175762306a36Sopenharmony_ci			 * is used as a flag to indicate that the file
175862306a36Sopenharmony_ci			 * has been already downloaded to the VUB300 chip
175962306a36Sopenharmony_ci			 */
176062306a36Sopenharmony_ci		} else if (0 == vub300->mmc->card->sdio_funcs) {
176162306a36Sopenharmony_ci			strncpy(vub300->vub_name, "SD memory device",
176262306a36Sopenharmony_ci				sizeof(vub300->vub_name));
176362306a36Sopenharmony_ci		} else {
176462306a36Sopenharmony_ci			download_offload_pseudocode(vub300);
176562306a36Sopenharmony_ci		}
176662306a36Sopenharmony_ci		send_command(vub300);
176762306a36Sopenharmony_ci		if (!data)
176862306a36Sopenharmony_ci			data_length = 0;
176962306a36Sopenharmony_ci		else if (MMC_DATA_READ & data->flags)
177062306a36Sopenharmony_ci			data_length = __command_read_data(vub300, cmd, data);
177162306a36Sopenharmony_ci		else
177262306a36Sopenharmony_ci			data_length = __command_write_data(vub300, cmd, data);
177362306a36Sopenharmony_ci		__vub300_command_response(vub300, cmd, data, data_length);
177462306a36Sopenharmony_ci		vub300->req = NULL;
177562306a36Sopenharmony_ci		vub300->cmd = NULL;
177662306a36Sopenharmony_ci		vub300->data = NULL;
177762306a36Sopenharmony_ci		if (cmd->error) {
177862306a36Sopenharmony_ci			if (cmd->error == -ENOMEDIUM)
177962306a36Sopenharmony_ci				check_vub300_port_status(vub300);
178062306a36Sopenharmony_ci			mutex_unlock(&vub300->cmd_mutex);
178162306a36Sopenharmony_ci			mmc_request_done(vub300->mmc, req);
178262306a36Sopenharmony_ci			kref_put(&vub300->kref, vub300_delete);
178362306a36Sopenharmony_ci			return;
178462306a36Sopenharmony_ci		} else {
178562306a36Sopenharmony_ci			construct_request_response(vub300, cmd);
178662306a36Sopenharmony_ci			vub300->resp_len = 0;
178762306a36Sopenharmony_ci			mutex_unlock(&vub300->cmd_mutex);
178862306a36Sopenharmony_ci			kref_put(&vub300->kref, vub300_delete);
178962306a36Sopenharmony_ci			mmc_request_done(vub300->mmc, req);
179062306a36Sopenharmony_ci			return;
179162306a36Sopenharmony_ci		}
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_cistatic int examine_cyclic_buffer(struct vub300_mmc_host *vub300,
179662306a36Sopenharmony_ci				 struct mmc_command *cmd, u8 Function)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_mmc_request */
179962306a36Sopenharmony_ci	u8 cmd0 = 0xFF & (cmd->arg >> 24);
180062306a36Sopenharmony_ci	u8 cmd1 = 0xFF & (cmd->arg >> 16);
180162306a36Sopenharmony_ci	u8 cmd2 = 0xFF & (cmd->arg >> 8);
180262306a36Sopenharmony_ci	u8 cmd3 = 0xFF & (cmd->arg >> 0);
180362306a36Sopenharmony_ci	int first = MAXREGMASK & vub300->fn[Function].offload_point;
180462306a36Sopenharmony_ci	struct offload_registers_access *rf = &vub300->fn[Function].reg[first];
180562306a36Sopenharmony_ci	if (cmd0 == rf->command_byte[0] &&
180662306a36Sopenharmony_ci	    cmd1 == rf->command_byte[1] &&
180762306a36Sopenharmony_ci	    cmd2 == rf->command_byte[2] &&
180862306a36Sopenharmony_ci	    cmd3 == rf->command_byte[3]) {
180962306a36Sopenharmony_ci		u8 checksum = 0x00;
181062306a36Sopenharmony_ci		cmd->resp[1] = checksum << 24;
181162306a36Sopenharmony_ci		cmd->resp[0] = (rf->Respond_Byte[0] << 24)
181262306a36Sopenharmony_ci			| (rf->Respond_Byte[1] << 16)
181362306a36Sopenharmony_ci			| (rf->Respond_Byte[2] << 8)
181462306a36Sopenharmony_ci			| (rf->Respond_Byte[3] << 0);
181562306a36Sopenharmony_ci		vub300->fn[Function].offload_point += 1;
181662306a36Sopenharmony_ci		vub300->fn[Function].offload_count -= 1;
181762306a36Sopenharmony_ci		vub300->total_offload_count -= 1;
181862306a36Sopenharmony_ci		return 1;
181962306a36Sopenharmony_ci	} else {
182062306a36Sopenharmony_ci		int delta = 1;	/* because it does not match the first one */
182162306a36Sopenharmony_ci		u8 register_count = vub300->fn[Function].offload_count - 1;
182262306a36Sopenharmony_ci		u32 register_point = vub300->fn[Function].offload_point + 1;
182362306a36Sopenharmony_ci		while (0 < register_count) {
182462306a36Sopenharmony_ci			int point = MAXREGMASK & register_point;
182562306a36Sopenharmony_ci			struct offload_registers_access *r =
182662306a36Sopenharmony_ci				&vub300->fn[Function].reg[point];
182762306a36Sopenharmony_ci			if (cmd0 == r->command_byte[0] &&
182862306a36Sopenharmony_ci			    cmd1 == r->command_byte[1] &&
182962306a36Sopenharmony_ci			    cmd2 == r->command_byte[2] &&
183062306a36Sopenharmony_ci			    cmd3 == r->command_byte[3]) {
183162306a36Sopenharmony_ci				u8 checksum = 0x00;
183262306a36Sopenharmony_ci				cmd->resp[1] = checksum << 24;
183362306a36Sopenharmony_ci				cmd->resp[0] = (r->Respond_Byte[0] << 24)
183462306a36Sopenharmony_ci					| (r->Respond_Byte[1] << 16)
183562306a36Sopenharmony_ci					| (r->Respond_Byte[2] << 8)
183662306a36Sopenharmony_ci					| (r->Respond_Byte[3] << 0);
183762306a36Sopenharmony_ci				vub300->fn[Function].offload_point += delta;
183862306a36Sopenharmony_ci				vub300->fn[Function].offload_count -= delta;
183962306a36Sopenharmony_ci				vub300->total_offload_count -= delta;
184062306a36Sopenharmony_ci				return 1;
184162306a36Sopenharmony_ci			} else {
184262306a36Sopenharmony_ci				register_point += 1;
184362306a36Sopenharmony_ci				register_count -= 1;
184462306a36Sopenharmony_ci				delta += 1;
184562306a36Sopenharmony_ci				continue;
184662306a36Sopenharmony_ci			}
184762306a36Sopenharmony_ci		}
184862306a36Sopenharmony_ci		return 0;
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_cistatic int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
185362306a36Sopenharmony_ci					       struct mmc_command *cmd)
185462306a36Sopenharmony_ci{
185562306a36Sopenharmony_ci	/* cmd_mutex is held by vub300_mmc_request */
185662306a36Sopenharmony_ci	u8 regs = vub300->dynamic_register_count;
185762306a36Sopenharmony_ci	u8 i = 0;
185862306a36Sopenharmony_ci	u8 func = FUN(cmd);
185962306a36Sopenharmony_ci	u32 reg = REG(cmd);
186062306a36Sopenharmony_ci	while (0 < regs--) {
186162306a36Sopenharmony_ci		if ((vub300->sdio_register[i].func_num == func) &&
186262306a36Sopenharmony_ci		    (vub300->sdio_register[i].sdio_reg == reg)) {
186362306a36Sopenharmony_ci			if (!vub300->sdio_register[i].prepared) {
186462306a36Sopenharmony_ci				return 0;
186562306a36Sopenharmony_ci			} else if ((0x80000000 & cmd->arg) == 0x80000000) {
186662306a36Sopenharmony_ci				/*
186762306a36Sopenharmony_ci				 * a write to a dynamic register
186862306a36Sopenharmony_ci				 * nullifies our offloaded value
186962306a36Sopenharmony_ci				 */
187062306a36Sopenharmony_ci				vub300->sdio_register[i].prepared = 0;
187162306a36Sopenharmony_ci				return 0;
187262306a36Sopenharmony_ci			} else {
187362306a36Sopenharmony_ci				u8 checksum = 0x00;
187462306a36Sopenharmony_ci				u8 rsp0 = 0x00;
187562306a36Sopenharmony_ci				u8 rsp1 = 0x00;
187662306a36Sopenharmony_ci				u8 rsp2 = vub300->sdio_register[i].response;
187762306a36Sopenharmony_ci				u8 rsp3 = vub300->sdio_register[i].regvalue;
187862306a36Sopenharmony_ci				vub300->sdio_register[i].prepared = 0;
187962306a36Sopenharmony_ci				cmd->resp[1] = checksum << 24;
188062306a36Sopenharmony_ci				cmd->resp[0] = (rsp0 << 24)
188162306a36Sopenharmony_ci					| (rsp1 << 16)
188262306a36Sopenharmony_ci					| (rsp2 << 8)
188362306a36Sopenharmony_ci					| (rsp3 << 0);
188462306a36Sopenharmony_ci				return 1;
188562306a36Sopenharmony_ci			}
188662306a36Sopenharmony_ci		} else {
188762306a36Sopenharmony_ci			i += 1;
188862306a36Sopenharmony_ci			continue;
188962306a36Sopenharmony_ci		}
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci	if (vub300->total_offload_count == 0)
189262306a36Sopenharmony_ci		return 0;
189362306a36Sopenharmony_ci	else if (vub300->fn[func].offload_count == 0)
189462306a36Sopenharmony_ci		return 0;
189562306a36Sopenharmony_ci	else
189662306a36Sopenharmony_ci		return examine_cyclic_buffer(vub300, cmd, func);
189762306a36Sopenharmony_ci}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_cistatic void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
190062306a36Sopenharmony_ci{				/* NOT irq */
190162306a36Sopenharmony_ci	struct mmc_command *cmd = req->cmd;
190262306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
190362306a36Sopenharmony_ci	if (!vub300->interface) {
190462306a36Sopenharmony_ci		cmd->error = -ESHUTDOWN;
190562306a36Sopenharmony_ci		mmc_request_done(mmc, req);
190662306a36Sopenharmony_ci		return;
190762306a36Sopenharmony_ci	} else {
190862306a36Sopenharmony_ci		struct mmc_data *data = req->data;
190962306a36Sopenharmony_ci		if (!vub300->card_powered) {
191062306a36Sopenharmony_ci			cmd->error = -ENOMEDIUM;
191162306a36Sopenharmony_ci			mmc_request_done(mmc, req);
191262306a36Sopenharmony_ci			return;
191362306a36Sopenharmony_ci		}
191462306a36Sopenharmony_ci		if (!vub300->card_present) {
191562306a36Sopenharmony_ci			cmd->error = -ENOMEDIUM;
191662306a36Sopenharmony_ci			mmc_request_done(mmc, req);
191762306a36Sopenharmony_ci			return;
191862306a36Sopenharmony_ci		}
191962306a36Sopenharmony_ci		if (vub300->usb_transport_fail) {
192062306a36Sopenharmony_ci			cmd->error = vub300->usb_transport_fail;
192162306a36Sopenharmony_ci			mmc_request_done(mmc, req);
192262306a36Sopenharmony_ci			return;
192362306a36Sopenharmony_ci		}
192462306a36Sopenharmony_ci		if (!vub300->interface) {
192562306a36Sopenharmony_ci			cmd->error = -ENODEV;
192662306a36Sopenharmony_ci			mmc_request_done(mmc, req);
192762306a36Sopenharmony_ci			return;
192862306a36Sopenharmony_ci		}
192962306a36Sopenharmony_ci		kref_get(&vub300->kref);
193062306a36Sopenharmony_ci		mutex_lock(&vub300->cmd_mutex);
193162306a36Sopenharmony_ci		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
193262306a36Sopenharmony_ci		/*
193362306a36Sopenharmony_ci		 * for performance we have to return immediately
193462306a36Sopenharmony_ci		 * if the requested data has been offloaded
193562306a36Sopenharmony_ci		 */
193662306a36Sopenharmony_ci		if (cmd->opcode == 52 &&
193762306a36Sopenharmony_ci		    satisfy_request_from_offloaded_data(vub300, cmd)) {
193862306a36Sopenharmony_ci			cmd->error = 0;
193962306a36Sopenharmony_ci			mutex_unlock(&vub300->cmd_mutex);
194062306a36Sopenharmony_ci			kref_put(&vub300->kref, vub300_delete);
194162306a36Sopenharmony_ci			mmc_request_done(mmc, req);
194262306a36Sopenharmony_ci			return;
194362306a36Sopenharmony_ci		} else {
194462306a36Sopenharmony_ci			vub300->cmd = cmd;
194562306a36Sopenharmony_ci			vub300->req = req;
194662306a36Sopenharmony_ci			vub300->data = data;
194762306a36Sopenharmony_ci			if (data)
194862306a36Sopenharmony_ci				vub300->datasize = data->blksz * data->blocks;
194962306a36Sopenharmony_ci			else
195062306a36Sopenharmony_ci				vub300->datasize = 0;
195162306a36Sopenharmony_ci			vub300_queue_cmnd_work(vub300);
195262306a36Sopenharmony_ci			mutex_unlock(&vub300->cmd_mutex);
195362306a36Sopenharmony_ci			kref_put(&vub300->kref, vub300_delete);
195462306a36Sopenharmony_ci			/*
195562306a36Sopenharmony_ci			 * the kernel lock diagnostics complain
195662306a36Sopenharmony_ci			 * if the cmd_mutex * is "passed on"
195762306a36Sopenharmony_ci			 * to the cmndwork thread,
195862306a36Sopenharmony_ci			 * so we must release it now
195962306a36Sopenharmony_ci			 * and re-acquire it in the cmndwork thread
196062306a36Sopenharmony_ci			 */
196162306a36Sopenharmony_ci		}
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_cistatic void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8],
196662306a36Sopenharmony_ci			      struct mmc_ios *ios)
196762306a36Sopenharmony_ci{
196862306a36Sopenharmony_ci	int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */
196962306a36Sopenharmony_ci	int retval;
197062306a36Sopenharmony_ci	u32 kHzClock;
197162306a36Sopenharmony_ci	if (ios->clock >= 48000000)
197262306a36Sopenharmony_ci		kHzClock = 48000;
197362306a36Sopenharmony_ci	else if (ios->clock >= 24000000)
197462306a36Sopenharmony_ci		kHzClock = 24000;
197562306a36Sopenharmony_ci	else if (ios->clock >= 20000000)
197662306a36Sopenharmony_ci		kHzClock = 20000;
197762306a36Sopenharmony_ci	else if (ios->clock >= 15000000)
197862306a36Sopenharmony_ci		kHzClock = 15000;
197962306a36Sopenharmony_ci	else if (ios->clock >= 200000)
198062306a36Sopenharmony_ci		kHzClock = 200;
198162306a36Sopenharmony_ci	else
198262306a36Sopenharmony_ci		kHzClock = 0;
198362306a36Sopenharmony_ci	{
198462306a36Sopenharmony_ci		int i;
198562306a36Sopenharmony_ci		u64 c = kHzClock;
198662306a36Sopenharmony_ci		for (i = 0; i < buf_array_size; i++) {
198762306a36Sopenharmony_ci			buf[i] = c;
198862306a36Sopenharmony_ci			c >>= 8;
198962306a36Sopenharmony_ci		}
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci	retval =
199262306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
199362306a36Sopenharmony_ci				SET_CLOCK_SPEED,
199462306a36Sopenharmony_ci				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
199562306a36Sopenharmony_ci				0x00, 0x00, buf, buf_array_size, 1000);
199662306a36Sopenharmony_ci	if (retval != 8) {
199762306a36Sopenharmony_ci		dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
199862306a36Sopenharmony_ci			" %dkHz failed with retval=%d\n", kHzClock, retval);
199962306a36Sopenharmony_ci	} else {
200062306a36Sopenharmony_ci		dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED"
200162306a36Sopenharmony_ci			" %dkHz\n", kHzClock);
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cistatic void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
200662306a36Sopenharmony_ci{				/* NOT irq */
200762306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
200862306a36Sopenharmony_ci	if (!vub300->interface)
200962306a36Sopenharmony_ci		return;
201062306a36Sopenharmony_ci	kref_get(&vub300->kref);
201162306a36Sopenharmony_ci	mutex_lock(&vub300->cmd_mutex);
201262306a36Sopenharmony_ci	if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) {
201362306a36Sopenharmony_ci		vub300->card_powered = 0;
201462306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
201562306a36Sopenharmony_ci				SET_SD_POWER,
201662306a36Sopenharmony_ci				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
201762306a36Sopenharmony_ci				0x0000, 0x0000, NULL, 0, 1000);
201862306a36Sopenharmony_ci		/* must wait for the VUB300 u-proc to boot up */
201962306a36Sopenharmony_ci		msleep(600);
202062306a36Sopenharmony_ci	} else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
202162306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
202262306a36Sopenharmony_ci				SET_SD_POWER,
202362306a36Sopenharmony_ci				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
202462306a36Sopenharmony_ci				0x0001, 0x0000, NULL, 0, 1000);
202562306a36Sopenharmony_ci		msleep(600);
202662306a36Sopenharmony_ci		vub300->card_powered = 1;
202762306a36Sopenharmony_ci	} else if (ios->power_mode == MMC_POWER_ON) {
202862306a36Sopenharmony_ci		u8 *buf = kmalloc(8, GFP_KERNEL);
202962306a36Sopenharmony_ci		if (buf) {
203062306a36Sopenharmony_ci			__set_clock_speed(vub300, buf, ios);
203162306a36Sopenharmony_ci			kfree(buf);
203262306a36Sopenharmony_ci		}
203362306a36Sopenharmony_ci	} else {
203462306a36Sopenharmony_ci		/* this should mean no change of state */
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci	mutex_unlock(&vub300->cmd_mutex);
203762306a36Sopenharmony_ci	kref_put(&vub300->kref, vub300_delete);
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_cistatic int vub300_mmc_get_ro(struct mmc_host *mmc)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
204362306a36Sopenharmony_ci	return vub300->read_only;
204462306a36Sopenharmony_ci}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_cistatic void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
204762306a36Sopenharmony_ci{				/* NOT irq */
204862306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
204962306a36Sopenharmony_ci	if (!vub300->interface)
205062306a36Sopenharmony_ci		return;
205162306a36Sopenharmony_ci	kref_get(&vub300->kref);
205262306a36Sopenharmony_ci	if (enable) {
205362306a36Sopenharmony_ci		set_current_state(TASK_RUNNING);
205462306a36Sopenharmony_ci		mutex_lock(&vub300->irq_mutex);
205562306a36Sopenharmony_ci		if (vub300->irqs_queued) {
205662306a36Sopenharmony_ci			vub300->irqs_queued -= 1;
205762306a36Sopenharmony_ci			mmc_signal_sdio_irq(vub300->mmc);
205862306a36Sopenharmony_ci		} else if (vub300->irq_disabled) {
205962306a36Sopenharmony_ci			vub300->irq_disabled = 0;
206062306a36Sopenharmony_ci			vub300->irq_enabled = 1;
206162306a36Sopenharmony_ci			vub300_queue_poll_work(vub300, 0);
206262306a36Sopenharmony_ci		} else if (vub300->irq_enabled) {
206362306a36Sopenharmony_ci			/* this should not happen, so we will just ignore it */
206462306a36Sopenharmony_ci		} else {
206562306a36Sopenharmony_ci			vub300->irq_enabled = 1;
206662306a36Sopenharmony_ci			vub300_queue_poll_work(vub300, 0);
206762306a36Sopenharmony_ci		}
206862306a36Sopenharmony_ci		mutex_unlock(&vub300->irq_mutex);
206962306a36Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
207062306a36Sopenharmony_ci	} else {
207162306a36Sopenharmony_ci		vub300->irq_enabled = 0;
207262306a36Sopenharmony_ci	}
207362306a36Sopenharmony_ci	kref_put(&vub300->kref, vub300_delete);
207462306a36Sopenharmony_ci}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_cistatic const struct mmc_host_ops vub300_mmc_ops = {
207762306a36Sopenharmony_ci	.request = vub300_mmc_request,
207862306a36Sopenharmony_ci	.set_ios = vub300_mmc_set_ios,
207962306a36Sopenharmony_ci	.get_ro = vub300_mmc_get_ro,
208062306a36Sopenharmony_ci	.enable_sdio_irq = vub300_enable_sdio_irq,
208162306a36Sopenharmony_ci};
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic int vub300_probe(struct usb_interface *interface,
208462306a36Sopenharmony_ci			const struct usb_device_id *id)
208562306a36Sopenharmony_ci{				/* NOT irq */
208662306a36Sopenharmony_ci	struct vub300_mmc_host *vub300;
208762306a36Sopenharmony_ci	struct usb_host_interface *iface_desc;
208862306a36Sopenharmony_ci	struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
208962306a36Sopenharmony_ci	int i;
209062306a36Sopenharmony_ci	int retval = -ENOMEM;
209162306a36Sopenharmony_ci	struct urb *command_out_urb;
209262306a36Sopenharmony_ci	struct urb *command_res_urb;
209362306a36Sopenharmony_ci	struct mmc_host *mmc;
209462306a36Sopenharmony_ci	char manufacturer[48];
209562306a36Sopenharmony_ci	char product[32];
209662306a36Sopenharmony_ci	char serial_number[32];
209762306a36Sopenharmony_ci	usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
209862306a36Sopenharmony_ci		   sizeof(manufacturer));
209962306a36Sopenharmony_ci	usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
210062306a36Sopenharmony_ci	usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
210162306a36Sopenharmony_ci		   sizeof(serial_number));
210262306a36Sopenharmony_ci	dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
210362306a36Sopenharmony_ci		 le16_to_cpu(udev->descriptor.idVendor),
210462306a36Sopenharmony_ci		 le16_to_cpu(udev->descriptor.idProduct),
210562306a36Sopenharmony_ci		 manufacturer, product, serial_number);
210662306a36Sopenharmony_ci	command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
210762306a36Sopenharmony_ci	if (!command_out_urb) {
210862306a36Sopenharmony_ci		retval = -ENOMEM;
210962306a36Sopenharmony_ci		goto error0;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci	command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
211262306a36Sopenharmony_ci	if (!command_res_urb) {
211362306a36Sopenharmony_ci		retval = -ENOMEM;
211462306a36Sopenharmony_ci		goto error1;
211562306a36Sopenharmony_ci	}
211662306a36Sopenharmony_ci	/* this also allocates memory for our VUB300 mmc host device */
211762306a36Sopenharmony_ci	mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
211862306a36Sopenharmony_ci	if (!mmc) {
211962306a36Sopenharmony_ci		retval = -ENOMEM;
212062306a36Sopenharmony_ci		dev_err(&udev->dev, "not enough memory for the mmc_host\n");
212162306a36Sopenharmony_ci		goto error4;
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci	/* MMC core transfer sizes tunable parameters */
212462306a36Sopenharmony_ci	mmc->caps = 0;
212562306a36Sopenharmony_ci	if (!force_1_bit_data_xfers)
212662306a36Sopenharmony_ci		mmc->caps |= MMC_CAP_4_BIT_DATA;
212762306a36Sopenharmony_ci	if (!force_polling_for_irqs)
212862306a36Sopenharmony_ci		mmc->caps |= MMC_CAP_SDIO_IRQ;
212962306a36Sopenharmony_ci	mmc->caps &= ~MMC_CAP_NEEDS_POLL;
213062306a36Sopenharmony_ci	/*
213162306a36Sopenharmony_ci	 * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
213262306a36Sopenharmony_ci	 * for devices which results in spurious CMD7's being
213362306a36Sopenharmony_ci	 * issued which stops some SDIO cards from working
213462306a36Sopenharmony_ci	 */
213562306a36Sopenharmony_ci	if (limit_speed_to_24_MHz) {
213662306a36Sopenharmony_ci		mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
213762306a36Sopenharmony_ci		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
213862306a36Sopenharmony_ci		mmc->f_max = 24000000;
213962306a36Sopenharmony_ci		dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
214062306a36Sopenharmony_ci	} else {
214162306a36Sopenharmony_ci		mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
214262306a36Sopenharmony_ci		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
214362306a36Sopenharmony_ci		mmc->f_max = 48000000;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci	mmc->f_min = 200000;
214662306a36Sopenharmony_ci	mmc->max_blk_count = 511;
214762306a36Sopenharmony_ci	mmc->max_blk_size = 512;
214862306a36Sopenharmony_ci	mmc->max_segs = 128;
214962306a36Sopenharmony_ci	if (force_max_req_size)
215062306a36Sopenharmony_ci		mmc->max_req_size = force_max_req_size * 1024;
215162306a36Sopenharmony_ci	else
215262306a36Sopenharmony_ci		mmc->max_req_size = 64 * 1024;
215362306a36Sopenharmony_ci	mmc->max_seg_size = mmc->max_req_size;
215462306a36Sopenharmony_ci	mmc->ocr_avail = 0;
215562306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_165_195;
215662306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_20_21;
215762306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_21_22;
215862306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_22_23;
215962306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_23_24;
216062306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_24_25;
216162306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_25_26;
216262306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_26_27;
216362306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_27_28;
216462306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_28_29;
216562306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_29_30;
216662306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_30_31;
216762306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_31_32;
216862306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_32_33;
216962306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_33_34;
217062306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_34_35;
217162306a36Sopenharmony_ci	mmc->ocr_avail |= MMC_VDD_35_36;
217262306a36Sopenharmony_ci	mmc->ops = &vub300_mmc_ops;
217362306a36Sopenharmony_ci	vub300 = mmc_priv(mmc);
217462306a36Sopenharmony_ci	vub300->mmc = mmc;
217562306a36Sopenharmony_ci	vub300->card_powered = 0;
217662306a36Sopenharmony_ci	vub300->bus_width = 0;
217762306a36Sopenharmony_ci	vub300->cmnd.head.block_size[0] = 0x00;
217862306a36Sopenharmony_ci	vub300->cmnd.head.block_size[1] = 0x00;
217962306a36Sopenharmony_ci	vub300->app_spec = 0;
218062306a36Sopenharmony_ci	mutex_init(&vub300->cmd_mutex);
218162306a36Sopenharmony_ci	mutex_init(&vub300->irq_mutex);
218262306a36Sopenharmony_ci	vub300->command_out_urb = command_out_urb;
218362306a36Sopenharmony_ci	vub300->command_res_urb = command_res_urb;
218462306a36Sopenharmony_ci	vub300->usb_timed_out = 0;
218562306a36Sopenharmony_ci	vub300->dynamic_register_count = 0;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
218862306a36Sopenharmony_ci		vub300->fn[i].offload_point = 0;
218962306a36Sopenharmony_ci		vub300->fn[i].offload_count = 0;
219062306a36Sopenharmony_ci	}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	vub300->total_offload_count = 0;
219362306a36Sopenharmony_ci	vub300->irq_enabled = 0;
219462306a36Sopenharmony_ci	vub300->irq_disabled = 0;
219562306a36Sopenharmony_ci	vub300->irqs_queued = 0;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
219862306a36Sopenharmony_ci		vub300->sdio_register[i++].activate = 0;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	vub300->udev = udev;
220162306a36Sopenharmony_ci	vub300->interface = interface;
220262306a36Sopenharmony_ci	vub300->cmnd_res_ep = 0;
220362306a36Sopenharmony_ci	vub300->cmnd_out_ep = 0;
220462306a36Sopenharmony_ci	vub300->data_inp_ep = 0;
220562306a36Sopenharmony_ci	vub300->data_out_ep = 0;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
220862306a36Sopenharmony_ci		vub300->fbs[i] = 512;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	/*
221162306a36Sopenharmony_ci	 *      set up the endpoint information
221262306a36Sopenharmony_ci	 *
221362306a36Sopenharmony_ci	 * use the first pair of bulk-in and bulk-out
221462306a36Sopenharmony_ci	 *     endpoints for Command/Response+Interrupt
221562306a36Sopenharmony_ci	 *
221662306a36Sopenharmony_ci	 * use the second pair of bulk-in and bulk-out
221762306a36Sopenharmony_ci	 *     endpoints for Data In/Out
221862306a36Sopenharmony_ci	 */
221962306a36Sopenharmony_ci	vub300->large_usb_packets = 0;
222062306a36Sopenharmony_ci	iface_desc = interface->cur_altsetting;
222162306a36Sopenharmony_ci	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
222262306a36Sopenharmony_ci		struct usb_endpoint_descriptor *endpoint =
222362306a36Sopenharmony_ci			&iface_desc->endpoint[i].desc;
222462306a36Sopenharmony_ci		dev_info(&vub300->udev->dev,
222562306a36Sopenharmony_ci			 "vub300 testing %s EndPoint(%d) %02X\n",
222662306a36Sopenharmony_ci			 usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
222762306a36Sopenharmony_ci			 usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
222862306a36Sopenharmony_ci			 "UNKNOWN", i, endpoint->bEndpointAddress);
222962306a36Sopenharmony_ci		if (endpoint->wMaxPacketSize > 64)
223062306a36Sopenharmony_ci			vub300->large_usb_packets = 1;
223162306a36Sopenharmony_ci		if (usb_endpoint_is_bulk_in(endpoint)) {
223262306a36Sopenharmony_ci			if (!vub300->cmnd_res_ep) {
223362306a36Sopenharmony_ci				vub300->cmnd_res_ep =
223462306a36Sopenharmony_ci					endpoint->bEndpointAddress;
223562306a36Sopenharmony_ci			} else if (!vub300->data_inp_ep) {
223662306a36Sopenharmony_ci				vub300->data_inp_ep =
223762306a36Sopenharmony_ci					endpoint->bEndpointAddress;
223862306a36Sopenharmony_ci			} else {
223962306a36Sopenharmony_ci				dev_warn(&vub300->udev->dev,
224062306a36Sopenharmony_ci					 "ignoring"
224162306a36Sopenharmony_ci					 " unexpected bulk_in endpoint");
224262306a36Sopenharmony_ci			}
224362306a36Sopenharmony_ci		} else if (usb_endpoint_is_bulk_out(endpoint)) {
224462306a36Sopenharmony_ci			if (!vub300->cmnd_out_ep) {
224562306a36Sopenharmony_ci				vub300->cmnd_out_ep =
224662306a36Sopenharmony_ci					endpoint->bEndpointAddress;
224762306a36Sopenharmony_ci			} else if (!vub300->data_out_ep) {
224862306a36Sopenharmony_ci				vub300->data_out_ep =
224962306a36Sopenharmony_ci					endpoint->bEndpointAddress;
225062306a36Sopenharmony_ci			} else {
225162306a36Sopenharmony_ci				dev_warn(&vub300->udev->dev,
225262306a36Sopenharmony_ci					 "ignoring"
225362306a36Sopenharmony_ci					 " unexpected bulk_out endpoint");
225462306a36Sopenharmony_ci			}
225562306a36Sopenharmony_ci		} else {
225662306a36Sopenharmony_ci			dev_warn(&vub300->udev->dev,
225762306a36Sopenharmony_ci				 "vub300 ignoring EndPoint(%d) %02X", i,
225862306a36Sopenharmony_ci				 endpoint->bEndpointAddress);
225962306a36Sopenharmony_ci		}
226062306a36Sopenharmony_ci	}
226162306a36Sopenharmony_ci	if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
226262306a36Sopenharmony_ci	    vub300->data_inp_ep && vub300->data_out_ep) {
226362306a36Sopenharmony_ci		dev_info(&vub300->udev->dev,
226462306a36Sopenharmony_ci			 "vub300 %s packets"
226562306a36Sopenharmony_ci			 " using EndPoints %02X %02X %02X %02X\n",
226662306a36Sopenharmony_ci			 vub300->large_usb_packets ? "LARGE" : "SMALL",
226762306a36Sopenharmony_ci			 vub300->cmnd_out_ep, vub300->cmnd_res_ep,
226862306a36Sopenharmony_ci			 vub300->data_out_ep, vub300->data_inp_ep);
226962306a36Sopenharmony_ci		/* we have the expected EndPoints */
227062306a36Sopenharmony_ci	} else {
227162306a36Sopenharmony_ci		dev_err(&vub300->udev->dev,
227262306a36Sopenharmony_ci		    "Could not find two sets of bulk-in/out endpoint pairs\n");
227362306a36Sopenharmony_ci		retval = -EINVAL;
227462306a36Sopenharmony_ci		goto error5;
227562306a36Sopenharmony_ci	}
227662306a36Sopenharmony_ci	retval =
227762306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
227862306a36Sopenharmony_ci				GET_HC_INF0,
227962306a36Sopenharmony_ci				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
228062306a36Sopenharmony_ci				0x0000, 0x0000, &vub300->hc_info,
228162306a36Sopenharmony_ci				sizeof(vub300->hc_info), 1000);
228262306a36Sopenharmony_ci	if (retval < 0)
228362306a36Sopenharmony_ci		goto error5;
228462306a36Sopenharmony_ci	retval =
228562306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
228662306a36Sopenharmony_ci				SET_ROM_WAIT_STATES,
228762306a36Sopenharmony_ci				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
228862306a36Sopenharmony_ci				firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
228962306a36Sopenharmony_ci	if (retval < 0)
229062306a36Sopenharmony_ci		goto error5;
229162306a36Sopenharmony_ci	dev_info(&vub300->udev->dev,
229262306a36Sopenharmony_ci		 "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
229362306a36Sopenharmony_ci		 (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
229462306a36Sopenharmony_ci		 (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
229562306a36Sopenharmony_ci		 mmc->f_max / 1000000,
229662306a36Sopenharmony_ci		 pad_input_to_usb_pkt ? "padding input data to" : "with",
229762306a36Sopenharmony_ci		 vub300->large_usb_packets ? 512 : 64);
229862306a36Sopenharmony_ci	retval =
229962306a36Sopenharmony_ci		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
230062306a36Sopenharmony_ci				GET_SYSTEM_PORT_STATUS,
230162306a36Sopenharmony_ci				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
230262306a36Sopenharmony_ci				0x0000, 0x0000, &vub300->system_port_status,
230362306a36Sopenharmony_ci				sizeof(vub300->system_port_status), 1000);
230462306a36Sopenharmony_ci	if (retval < 0) {
230562306a36Sopenharmony_ci		goto error5;
230662306a36Sopenharmony_ci	} else if (sizeof(vub300->system_port_status) == retval) {
230762306a36Sopenharmony_ci		vub300->card_present =
230862306a36Sopenharmony_ci			(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
230962306a36Sopenharmony_ci		vub300->read_only =
231062306a36Sopenharmony_ci			(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
231162306a36Sopenharmony_ci	} else {
231262306a36Sopenharmony_ci		retval = -EINVAL;
231362306a36Sopenharmony_ci		goto error5;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci	usb_set_intfdata(interface, vub300);
231662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
231762306a36Sopenharmony_ci	INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
231862306a36Sopenharmony_ci	INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
231962306a36Sopenharmony_ci	kref_init(&vub300->kref);
232062306a36Sopenharmony_ci	timer_setup(&vub300->sg_transfer_timer, vub300_sg_timed_out, 0);
232162306a36Sopenharmony_ci	kref_get(&vub300->kref);
232262306a36Sopenharmony_ci	timer_setup(&vub300->inactivity_timer,
232362306a36Sopenharmony_ci		    vub300_inactivity_timer_expired, 0);
232462306a36Sopenharmony_ci	vub300->inactivity_timer.expires = jiffies + HZ;
232562306a36Sopenharmony_ci	add_timer(&vub300->inactivity_timer);
232662306a36Sopenharmony_ci	if (vub300->card_present)
232762306a36Sopenharmony_ci		dev_info(&vub300->udev->dev,
232862306a36Sopenharmony_ci			 "USB vub300 remote SDIO host controller[%d]"
232962306a36Sopenharmony_ci			 "connected with SD/SDIO card inserted\n",
233062306a36Sopenharmony_ci			 interface_to_InterfaceNumber(interface));
233162306a36Sopenharmony_ci	else
233262306a36Sopenharmony_ci		dev_info(&vub300->udev->dev,
233362306a36Sopenharmony_ci			 "USB vub300 remote SDIO host controller[%d]"
233462306a36Sopenharmony_ci			 "connected with no SD/SDIO card inserted\n",
233562306a36Sopenharmony_ci			 interface_to_InterfaceNumber(interface));
233662306a36Sopenharmony_ci	retval = mmc_add_host(mmc);
233762306a36Sopenharmony_ci	if (retval)
233862306a36Sopenharmony_ci		goto error6;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	return 0;
234162306a36Sopenharmony_cierror6:
234262306a36Sopenharmony_ci	del_timer_sync(&vub300->inactivity_timer);
234362306a36Sopenharmony_cierror5:
234462306a36Sopenharmony_ci	mmc_free_host(mmc);
234562306a36Sopenharmony_ci	/*
234662306a36Sopenharmony_ci	 * and hence also frees vub300
234762306a36Sopenharmony_ci	 * which is contained at the end of struct mmc
234862306a36Sopenharmony_ci	 */
234962306a36Sopenharmony_cierror4:
235062306a36Sopenharmony_ci	usb_free_urb(command_res_urb);
235162306a36Sopenharmony_cierror1:
235262306a36Sopenharmony_ci	usb_free_urb(command_out_urb);
235362306a36Sopenharmony_cierror0:
235462306a36Sopenharmony_ci	usb_put_dev(udev);
235562306a36Sopenharmony_ci	return retval;
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cistatic void vub300_disconnect(struct usb_interface *interface)
235962306a36Sopenharmony_ci{				/* NOT irq */
236062306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = usb_get_intfdata(interface);
236162306a36Sopenharmony_ci	if (!vub300 || !vub300->mmc) {
236262306a36Sopenharmony_ci		return;
236362306a36Sopenharmony_ci	} else {
236462306a36Sopenharmony_ci		struct mmc_host *mmc = vub300->mmc;
236562306a36Sopenharmony_ci		if (!vub300->mmc) {
236662306a36Sopenharmony_ci			return;
236762306a36Sopenharmony_ci		} else {
236862306a36Sopenharmony_ci			int ifnum = interface_to_InterfaceNumber(interface);
236962306a36Sopenharmony_ci			usb_set_intfdata(interface, NULL);
237062306a36Sopenharmony_ci			/* prevent more I/O from starting */
237162306a36Sopenharmony_ci			vub300->interface = NULL;
237262306a36Sopenharmony_ci			kref_put(&vub300->kref, vub300_delete);
237362306a36Sopenharmony_ci			mmc_remove_host(mmc);
237462306a36Sopenharmony_ci			pr_info("USB vub300 remote SDIO host controller[%d]"
237562306a36Sopenharmony_ci				" now disconnected", ifnum);
237662306a36Sopenharmony_ci			return;
237762306a36Sopenharmony_ci		}
237862306a36Sopenharmony_ci	}
237962306a36Sopenharmony_ci}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci#ifdef CONFIG_PM
238262306a36Sopenharmony_cistatic int vub300_suspend(struct usb_interface *intf, pm_message_t message)
238362306a36Sopenharmony_ci{
238462306a36Sopenharmony_ci	return 0;
238562306a36Sopenharmony_ci}
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_cistatic int vub300_resume(struct usb_interface *intf)
238862306a36Sopenharmony_ci{
238962306a36Sopenharmony_ci	return 0;
239062306a36Sopenharmony_ci}
239162306a36Sopenharmony_ci#else
239262306a36Sopenharmony_ci#define vub300_suspend NULL
239362306a36Sopenharmony_ci#define vub300_resume NULL
239462306a36Sopenharmony_ci#endif
239562306a36Sopenharmony_cistatic int vub300_pre_reset(struct usb_interface *intf)
239662306a36Sopenharmony_ci{				/* NOT irq */
239762306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
239862306a36Sopenharmony_ci	mutex_lock(&vub300->cmd_mutex);
239962306a36Sopenharmony_ci	return 0;
240062306a36Sopenharmony_ci}
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_cistatic int vub300_post_reset(struct usb_interface *intf)
240362306a36Sopenharmony_ci{				/* NOT irq */
240462306a36Sopenharmony_ci	struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
240562306a36Sopenharmony_ci	/* we are sure no URBs are active - no locking needed */
240662306a36Sopenharmony_ci	vub300->errors = -EPIPE;
240762306a36Sopenharmony_ci	mutex_unlock(&vub300->cmd_mutex);
240862306a36Sopenharmony_ci	return 0;
240962306a36Sopenharmony_ci}
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_cistatic struct usb_driver vub300_driver = {
241262306a36Sopenharmony_ci	.name = "vub300",
241362306a36Sopenharmony_ci	.probe = vub300_probe,
241462306a36Sopenharmony_ci	.disconnect = vub300_disconnect,
241562306a36Sopenharmony_ci	.suspend = vub300_suspend,
241662306a36Sopenharmony_ci	.resume = vub300_resume,
241762306a36Sopenharmony_ci	.pre_reset = vub300_pre_reset,
241862306a36Sopenharmony_ci	.post_reset = vub300_post_reset,
241962306a36Sopenharmony_ci	.id_table = vub300_table,
242062306a36Sopenharmony_ci	.supports_autosuspend = 1,
242162306a36Sopenharmony_ci};
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_cistatic int __init vub300_init(void)
242462306a36Sopenharmony_ci{				/* NOT irq */
242562306a36Sopenharmony_ci	int result;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X",
242862306a36Sopenharmony_ci		firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout);
242962306a36Sopenharmony_ci	cmndworkqueue = create_singlethread_workqueue("kvub300c");
243062306a36Sopenharmony_ci	if (!cmndworkqueue) {
243162306a36Sopenharmony_ci		pr_err("not enough memory for the REQUEST workqueue");
243262306a36Sopenharmony_ci		result = -ENOMEM;
243362306a36Sopenharmony_ci		goto out1;
243462306a36Sopenharmony_ci	}
243562306a36Sopenharmony_ci	pollworkqueue = create_singlethread_workqueue("kvub300p");
243662306a36Sopenharmony_ci	if (!pollworkqueue) {
243762306a36Sopenharmony_ci		pr_err("not enough memory for the IRQPOLL workqueue");
243862306a36Sopenharmony_ci		result = -ENOMEM;
243962306a36Sopenharmony_ci		goto out2;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci	deadworkqueue = create_singlethread_workqueue("kvub300d");
244262306a36Sopenharmony_ci	if (!deadworkqueue) {
244362306a36Sopenharmony_ci		pr_err("not enough memory for the EXPIRED workqueue");
244462306a36Sopenharmony_ci		result = -ENOMEM;
244562306a36Sopenharmony_ci		goto out3;
244662306a36Sopenharmony_ci	}
244762306a36Sopenharmony_ci	result = usb_register(&vub300_driver);
244862306a36Sopenharmony_ci	if (result) {
244962306a36Sopenharmony_ci		pr_err("usb_register failed. Error number %d", result);
245062306a36Sopenharmony_ci		goto out4;
245162306a36Sopenharmony_ci	}
245262306a36Sopenharmony_ci	return 0;
245362306a36Sopenharmony_ciout4:
245462306a36Sopenharmony_ci	destroy_workqueue(deadworkqueue);
245562306a36Sopenharmony_ciout3:
245662306a36Sopenharmony_ci	destroy_workqueue(pollworkqueue);
245762306a36Sopenharmony_ciout2:
245862306a36Sopenharmony_ci	destroy_workqueue(cmndworkqueue);
245962306a36Sopenharmony_ciout1:
246062306a36Sopenharmony_ci	return result;
246162306a36Sopenharmony_ci}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_cistatic void __exit vub300_exit(void)
246462306a36Sopenharmony_ci{
246562306a36Sopenharmony_ci	usb_deregister(&vub300_driver);
246662306a36Sopenharmony_ci	flush_workqueue(cmndworkqueue);
246762306a36Sopenharmony_ci	flush_workqueue(pollworkqueue);
246862306a36Sopenharmony_ci	flush_workqueue(deadworkqueue);
246962306a36Sopenharmony_ci	destroy_workqueue(cmndworkqueue);
247062306a36Sopenharmony_ci	destroy_workqueue(pollworkqueue);
247162306a36Sopenharmony_ci	destroy_workqueue(deadworkqueue);
247262306a36Sopenharmony_ci}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_cimodule_init(vub300_init);
247562306a36Sopenharmony_cimodule_exit(vub300_exit);
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ciMODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>");
247862306a36Sopenharmony_ciMODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver");
247962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2480