summaryrefslogblamecommitdiffstats
path: root/drivers/mmc/host/vub300.c
blob: 1fe68137a30f2dcf93fbe3eb5aa800caf08becde (plain) (tree)
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
































































































































































































































                                                                         
                                  


                                                                                
                                 



                                                                     
                                       


                                                                           
                                   



                                                            
                                   
















                                                                              
                                                  





                                                                               
                                                    







































































































































































































































































































                                                                                
         











































































                                                                                
















                                                         
                                 










                                                                           
























































                                                                           
                                                      













                                                           
                                                                 
                                             

                                                                      
























































                                                                                
                                                                             

























































































































































































































































































































































































                                                                                 
                                                     
 

                                                                       




























































                                                                                 

                                                        








































                                                                                 

                                                        



















































                                                                             





                                                                    



















                                                                             
         

























































































































































































































































                                                                                  

                                                         


































































































































                                                                                
                                                                        






































































































































                                                                               
         






















































































































































































                                                                                 
                                                                         




                                                                       
                                                   









                                                        
                                       















                                                                              

                                                         



                                                       




                                                       





                                                                         
                                                                            





































































































































































































                                                                                 
                                                                        
                                

                                                        




















                                                                     
                                      

                                      
       
                          




























                                                                            
                 



                                                    
                 

























































































                                                                              
/*
 * Remote VUB300 SDIO/SDmem Host Controller Driver
 *
 * Copyright (C) 2010 Elan Digital Systems Limited
 *
 * based on USB Skeleton driver - 2.2
 *
 * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2
 *
 * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot
 *         Any SDIO/SDmem/MMC device plugged into the VUB300 will appear,
 *         by virtue of this driver, to have been plugged into a local
 *         SDIO host controller, similar to, say, a PCI Ricoh controller
 *         This is because this kernel device driver is both a USB 2.0
 *         client device driver AND an MMC host controller driver. Thus
 *         if there is an existing driver for the inserted SDIO/SDmem/MMC
 *         device then that driver will be used by the kernel to manage
 *         the device in exactly the same fashion as if it had been
 *         directly plugged into, say, a local pci bus Ricoh controller
 *
 * RANT: this driver was written using a display 128x48 - converting it
 *       to a line width of 80 makes it very difficult to support. In
 *       particular functions have been broken down into sub functions
 *       and the original meaningful names have been shortened into
 *       cryptic ones.
 *       The problem is that executing a fragment of code subject to
 *       two conditions means an indentation of 24, thus leaving only
 *       56 characters for a C statement. And that is quite ridiculous!
 *
 * Data types: data passed to/from the VUB300 is fixed to a number of
 *             bits and driver data fields reflect that limit by using
 *             u8, u16, u32
 */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/workqueue.h>
#include <linux/ctype.h>
#include <linux/firmware.h>
#include <linux/scatterlist.h>

struct host_controller_info {
	u8 info_size;
	u16 firmware_version;
	u8 number_of_ports;
} __packed;

#define FIRMWARE_BLOCK_BOUNDARY 1024
struct sd_command_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	u8 command_type; /* Bit7 - Rd/Wr */
	u8 command_index;
	u8 transfer_size[4]; /* ReadSize + ReadSize */
	u8 response_type;
	u8 arguments[4];
	u8 block_count[2];
	u8 block_size[2];
	u8 block_boundary[2];
	u8 reserved[44]; /* to pad out to 64 bytes */
} __packed;

struct sd_irqpoll_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	u8 command_type; /* Bit7 - Rd/Wr */
	u8 padding[16]; /* don't ask why !! */
	u8 poll_timeout_msb;
	u8 poll_timeout_lsb;
	u8 reserved[42]; /* to pad out to 64 bytes */
} __packed;

struct sd_common_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
} __packed;

struct sd_response_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	u8 command_type;
	u8 command_index;
	u8 command_response[0];
} __packed;

struct sd_status_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	u16 port_flags;
	u32 sdio_clock;
	u16 host_header_size;
	u16 func_header_size;
	u16 ctrl_header_size;
} __packed;

struct sd_error_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	u8 error_code;
} __packed;

struct sd_interrupt_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
} __packed;

struct offload_registers_access {
	u8 command_byte[4];
	u8 Respond_Byte[4];
} __packed;

#define INTERRUPT_REGISTER_ACCESSES 15
struct sd_offloaded_interrupt {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES];
} __packed;

struct sd_register_header {
	u8 header_size;
	u8 header_type;
	u8 port_number;
	u8 command_type;
	u8 command_index;
	u8 command_response[6];
} __packed;

#define PIGGYBACK_REGISTER_ACCESSES 14
struct sd_offloaded_piggyback {
	struct sd_register_header sdio;
	struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES];
} __packed;

union sd_response {
	struct sd_common_header common;
	struct sd_status_header status;
	struct sd_error_header error;
	struct sd_interrupt_header interrupt;
	struct sd_response_header response;
	struct sd_offloaded_interrupt irq;
	struct sd_offloaded_piggyback pig;
} __packed;

union sd_command {
	struct sd_command_header head;
	struct sd_irqpoll_header poll;
} __packed;

enum SD_RESPONSE_TYPE {
	SDRT_UNSPECIFIED = 0,
	SDRT_NONE,
	SDRT_1,
	SDRT_1B,
	SDRT_2,
	SDRT_3,
	SDRT_4,
	SDRT_5,
	SDRT_5B,
	SDRT_6,
	SDRT_7,
};

#define RESPONSE_INTERRUPT			0x01
#define RESPONSE_ERROR				0x02
#define RESPONSE_STATUS				0x03
#define RESPONSE_IRQ_DISABLED			0x05
#define RESPONSE_IRQ_ENABLED			0x06
#define RESPONSE_PIGGYBACKED			0x07
#define RESPONSE_NO_INTERRUPT			0x08
#define RESPONSE_PIG_DISABLED			0x09
#define RESPONSE_PIG_ENABLED			0x0A
#define SD_ERROR_1BIT_TIMEOUT			0x01
#define SD_ERROR_4BIT_TIMEOUT			0x02
#define SD_ERROR_1BIT_CRC_WRONG			0x03
#define SD_ERROR_4BIT_CRC_WRONG			0x04
#define SD_ERROR_1BIT_CRC_ERROR			0x05
#define SD_ERROR_4BIT_CRC_ERROR			0x06
#define SD_ERROR_NO_CMD_ENDBIT			0x07
#define SD_ERROR_NO_1BIT_DATEND			0x08
#define SD_ERROR_NO_4BIT_DATEND			0x09
#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT	0x0A
#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT	0x0B
#define SD_ERROR_ILLEGAL_COMMAND		0x0C
#define SD_ERROR_NO_DEVICE			0x0D
#define SD_ERROR_TRANSFER_LENGTH		0x0E
#define SD_ERROR_1BIT_DATA_TIMEOUT		0x0F
#define SD_ERROR_4BIT_DATA_TIMEOUT		0x10
#define SD_ERROR_ILLEGAL_STATE			0x11
#define SD_ERROR_UNKNOWN_ERROR			0x12
#define SD_ERROR_RESERVED_ERROR			0x13
#define SD_ERROR_INVALID_FUNCTION		0x14
#define SD_ERROR_OUT_OF_RANGE			0x15
#define SD_ERROR_STAT_CMD			0x16
#define SD_ERROR_STAT_DATA			0x17
#define SD_ERROR_STAT_CMD_TIMEOUT		0x18
#define SD_ERROR_SDCRDY_STUCK			0x19
#define SD_ERROR_UNHANDLED			0x1A
#define SD_ERROR_OVERRUN			0x1B
#define SD_ERROR_PIO_TIMEOUT			0x1C

#define FUN(c) (0x000007 & (c->arg>>28))
#define REG(c) (0x01FFFF & (c->arg>>9))

static bool limit_speed_to_24_MHz;
module_param(limit_speed_to_24_MHz, bool, 0644);
MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");

static bool pad_input_to_usb_pkt;
module_param(pad_input_to_usb_pkt, bool, 0644);
MODULE_PARM_DESC(pad_input_to_usb_pkt,
		 "Pad USB data input transfers to whole USB Packet");

static bool disable_offload_processing;
module_param(disable_offload_processing, bool, 0644);
MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");

static bool force_1_bit_data_xfers;
module_param(force_1_bit_data_xfers, bool, 0644);
MODULE_PARM_DESC(force_1_bit_data_xfers,
		 "Force SDIO Data Transfers to 1-bit Mode");

static bool force_polling_for_irqs;
module_param(force_polling_for_irqs, bool, 0644);
MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");

static int firmware_irqpoll_timeout = 1024;
module_param(firmware_irqpoll_timeout, int, 0644);
MODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout");

static int force_max_req_size = 128;
module_param(force_max_req_size, int, 0644);
MODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes");

#ifdef SMSC_DEVELOPMENT_BOARD
static int firmware_rom_wait_states = 0x04;
#else
static int firmware_rom_wait_states = 0x1C;
#endif

module_param(firmware_rom_wait_states, int, 0644);
MODULE_PARM_DESC(firmware_rom_wait_states,
		 "ROM wait states byte=RRRIIEEE (Reserved Internal External)");

#define ELAN_VENDOR_ID		0x2201
#define VUB300_VENDOR_ID	0x0424
#define VUB300_PRODUCT_ID	0x012C
static const struct usb_device_id vub300_table[] = {
	{USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
	{USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
	{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, vub300_table);

static struct workqueue_struct *cmndworkqueue;
static struct workqueue_struct *pollworkqueue;
static struct workqueue_struct *deadworkqueue;

static inline int interface_to_InterfaceNumber(struct usb_interface *interface)
{
	if (!interface)
		return -1;
	if (!interface->cur_altsetting)
		return -1;
	return interface->cur_altsetting->desc.bInterfaceNumber;
}

struct sdio_register {
	unsigned func_num:3;
	unsigned sdio_reg:17;
	unsigned activate:1;
	unsigned prepared:1;
	unsigned regvalue:8;
	unsigned response:8;
	unsigned sparebit:26;
};

struct vub300_mmc_host {
	struct usb_device *udev;
	struct usb_interface *interface;
	struct kref kref;
	struct mutex cmd_mutex;
	struct mutex irq_mutex;
	char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */
	u8 cmnd_out_ep; /* EndPoint for commands */
	u8 cmnd_res_ep; /* EndPoint for responses */
	u8 data_out_ep; /* EndPoint for out data */
	u8 data_inp_ep; /* EndPoint for inp data */
	bool card_powered;
	bool card_present;
	bool read_only;
	bool large_usb_packets;
	bool app_spec; /* ApplicationSpecific */
	bool irq_enabled; /* by the MMC CORE */
	bool irq_disabled; /* in the firmware */
	unsigned bus_width:4;
	u8 total_offload_count;
	u8 dynamic_register_count;
	u8 resp_len;
	u32 datasize;
	int errors;
	int usb_transport_fail;
	int usb_timed_out;
	int irqs_queued;
	struct sdio_register sdio_register[16];
	struct offload_interrupt_function_register {
#define MAXREGBITS 4
#define MAXREGS (1<<MAXREGBITS)
#define MAXREGMASK (MAXREGS-1)
		u8 offload_count;
		u32 offload_point;
		struct offload_registers_access reg[MAXREGS];
	} fn[8];
	u16 fbs[8]; /* Function Block Size */
	struct mmc_command *cmd;
	struct mmc_request *req;
	struct mmc_data *data;
	struct mmc_host *mmc;
	struct urb *urb;
	struct urb *command_out_urb;
	struct urb *command_res_urb;
	struct completion command_complete;
	struct completion irqpoll_complete;
	union sd_command cmnd;
	union sd_response resp;
	struct timer_list sg_transfer_timer;
	struct usb_sg_request sg_request;
	struct timer_list inactivity_timer;
	struct work_struct deadwork;
	struct work_struct cmndwork;
	struct delayed_work pollwork;
	struct host_controller_info hc_info;
	struct sd_status_header system_port_status;
	u8 padded_buffer[64];
};

#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref)
#define SET_TRANSFER_PSEUDOCODE		21
#define SET_INTERRUPT_PSEUDOCODE	20
#define SET_FAILURE_MODE		18
#define SET_ROM_WAIT_STATES		16
#define SET_IRQ_ENABLE			13
#define SET_CLOCK_SPEED			11
#define SET_FUNCTION_BLOCK_SIZE		9
#define SET_SD_DATA_MODE		6
#define SET_SD_POWER			4
#define ENTER_DFU_MODE			3
#define GET_HC_INF0			1
#define GET_SYSTEM_PORT_STATUS		0

static void vub300_delete(struct kref *kref)
{				/* kref callback - softirq */
	struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
	struct mmc_host *mmc = vub300->mmc;
	usb_free_urb(vub300->command_out_urb);
	vub300->command_out_urb = NULL;
	usb_free_urb(vub300->command_res_urb);
	vub300->command_res_urb = NULL;
	usb_put_dev(vub300->udev);
	mmc_free_host(mmc);
	/*
	 * and hence also frees vub300
	 * which is contained at the end of struct mmc
	 */
}

static void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300)
{
	kref_get(&vub300->kref);
	if (queue_work(cmndworkqueue, &vub300->cmndwork)) {
		/*
		 * then the cmndworkqueue was not previously
		 * running and the above get ref is obvious
		 * required and will be put when the thread
		 * terminates by a specific call
		 */
	} else {
		/*
		 * the cmndworkqueue was already running from
		 * a previous invocation and thus to keep the
		 * kref counts correct we must undo the get
		 */
		kref_put(&vub300->kref, vub300_delete);
	}
}

static void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay)
{
	kref_get(&vub300->kref);
	if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) {
		/*
		 * then the pollworkqueue was not previously
		 * running and the above get ref is obvious
		 * required and will be put when the thread
		 * terminates by a specific call
		 */
	} else {
		/*
		 * the pollworkqueue was already running from
		 * a previous invocation and thus to keep the
		 * kref counts correct we must undo the get
		 */
		kref_put(&vub300->kref, vub300_delete);
	}
}

static void vub300_queue_dead_work(struct vub300_mmc_host *vub300)
{
	kref_get(&vub300->kref);
	if (queue_work(deadworkqueue, &vub300->deadwork)) {
		/*
		 * then the deadworkqueue was not previously
		 * running and the above get ref is obvious
		 * required and will be put when the thread
		 * terminates by a specific call
		 */
	} else {
		/*
		 * the deadworkqueue was already running from
		 * a previous invocation and thus to keep the
		 * kref counts correct we must undo the get
		 */
		kref_put(&vub300->kref, vub300_delete);
	}
}

static void irqpoll_res_completed(struct urb *urb)
{				/* urb completion handler - hardirq */
	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
	if (urb->status)
		vub300->usb_transport_fail = urb->status;
	complete(&vub300->irqpoll_complete);
}

static void irqpoll_out_completed(struct urb *urb)
{				/* urb completion handler - hardirq */
	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
	if (urb->status) {
		vub300->usb_transport_fail = urb->status;
		complete(&vub300->irqpoll_complete);
		return;
	} else {
		int ret;
		unsigned int pipe =
			usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
		usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
				  &vub300->resp, sizeof(vub300->resp),
				  irqpoll_res_completed, vub300);
		vub300->command_res_urb->actual_length = 0;
		ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
		if (ret) {
			vub300->usb_transport_fail = ret;
			complete(&vub300->irqpoll_complete);
		}
		return;
	}
}

static void send_irqpoll(struct vub300_mmc_host *vub300)
{
	/* cmd_mutex is held by vub300_pollwork_thread */
	int retval;
	int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout);
	vub300->cmnd.poll.header_size = 22;
	vub300->cmnd.poll.header_type = 1;
	vub300->cmnd.poll.port_number = 0;
	vub300->cmnd.poll.command_type = 2;
	vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout;
	vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8);
	usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
			  usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep)
			  , &vub300->cmnd, sizeof(vub300->cmnd)
			  , irqpoll_out_completed, vub300);
	retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
	if (0 > retval) {
		vub300->usb_transport_fail = retval;
		vub300_queue_poll_work(vub300, 1);
		complete(&vub300->irqpoll_complete);
		return;
	} else {
		return;
	}
}

static void new_system_port_status(struct vub300_mmc_host *vub300)
{
	int old_card_present = vub300->card_present;
	int new_card_present =
		(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
	vub300->read_only =
		(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
	if (new_card_present && !old_card_present) {
		dev_info(&vub300->udev->dev, "card just inserted\n");
		vub300->card_present = 1;
		vub300->bus_width = 0;
		if (disable_offload_processing)
			strncpy(vub300->vub_name, "EMPTY Processing Disabled",
				sizeof(vub300->vub_name));
		else
			vub300->vub_name[0] = 0;
		mmc_detect_change(vub300->mmc, 1);
	} else if (!new_card_present && old_card_present) {
		dev_info(&vub300->udev->dev, "card just ejected\n");
		vub300->card_present = 0;
		mmc_detect_change(vub300->mmc, 0);
	} else {
		/* no change */
	}
}

static void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300,
					struct offload_registers_access
					*register_access, u8 func)
{
	u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count;
	memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access,
	       sizeof(struct offload_registers_access));
	vub300->fn[func].offload_count += 1;
	vub300->total_offload_count += 1;
}

static void add_offloaded_reg(struct vub300_mmc_host *vub300,
			      struct offload_registers_access *register_access)
{
	u32 Register = ((0x03 & register_access->command_byte[0]) << 15)
			| ((0xFF & register_access->command_byte[1]) << 7)
			| ((0xFE & register_access->command_byte[2]) >> 1);
	u8 func = ((0x70 & register_access->command_byte[0]) >> 4);
	u8 regs = vub300->dynamic_register_count;
	u8 i = 0;
	while (0 < regs-- && 1 == vub300->sdio_register[i].activate) {
		if (vub300->sdio_register[i].func_num == func &&
		    vub300->sdio_register[i].sdio_reg == Register) {
			if (vub300->sdio_register[i].prepared == 0)
				vub300->sdio_register[i].prepared = 1;
			vub300->sdio_register[i].response =
				register_access->Respond_Byte[2];
			vub300->sdio_register[i].regvalue =
				register_access->Respond_Byte[3];
			return;
		} else {
			i += 1;
			continue;
		}
	}
	__add_offloaded_reg_to_fifo(vub300, register_access, func);
}

static void check_vub300_port_status(struct vub300_mmc_host *vub300)
{
	/*
	 * cmd_mutex is held by vub300_pollwork_thread,
	 * vub300_deadwork_thread or vub300_cmndwork_thread
	 */
	int retval;
	retval =
		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
				GET_SYSTEM_PORT_STATUS,
				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				0x0000, 0x0000, &vub300->system_port_status,
				sizeof(vub300->system_port_status), HZ);
	if (sizeof(vub300->system_port_status) == retval)
		new_system_port_status(vub300);
}

static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
{
	/* cmd_mutex is held by vub300_pollwork_thread */
	if (vub300->command_res_urb->actual_length == 0)
		return;

	switch (vub300->resp.common.header_type) {
	case RESPONSE_INTERRUPT:
		mutex_lock(&vub300->irq_mutex);
		if (vub300->irq_enabled)
			mmc_signal_sdio_irq(vub300->mmc);
		else
			vub300->irqs_queued += 1;
		vub300->irq_disabled = 1;
		mutex_unlock(&vub300->irq_mutex);
		break;
	case RESPONSE_ERROR:
		if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE)
			check_vub300_port_status(vub300);
		break;
	case RESPONSE_STATUS:
		vub300->system_port_status = vub300->resp.status;
		new_system_port_status(vub300);
		if (!vub300->card_present)
			vub300_queue_poll_work(vub300, HZ / 5);
		break;
	case RESPONSE_IRQ_DISABLED:
	{
		int offloaded_data_length = vub300->resp.common.header_size - 3;
		int register_count = offloaded_data_length >> 3;
		int ri = 0;
		while (register_count--) {
			add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
			ri += 1;
		}
		mutex_lock(&vub300->irq_mutex);
		if (vub300->irq_enabled)
			mmc_signal_sdio_irq(vub300->mmc);
		else
			vub300->irqs_queued += 1;
		vub300->irq_disabled = 1;
		mutex_unlock(&vub300->irq_mutex);
		break;
	}
	case RESPONSE_IRQ_ENABLED:
	{
		int offloaded_data_length = vub300->resp.common.header_size - 3;
		int register_count = offloaded_data_length >> 3;
		int ri = 0;
		while (register_count--) {
			add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
			ri += 1;
		}
		mutex_lock(&vub300->irq_mutex);
		if (vub300->irq_enabled)
			mmc_signal_sdio_irq(vub300->mmc);
		else
			vub300->irqs_queued += 1;
		vub300->irq_disabled = 0;
		mutex_unlock(&vub300->irq_mutex);
		break;
	}
	case RESPONSE_NO_INTERRUPT:
		vub300_queue_poll_work(vub300, 1);
		break;
	default:
		break;
	}
}

static void __do_poll(struct vub300_mmc_host *vub300)
{
	/* cmd_mutex is held by vub300_pollwork_thread */
	unsigned long commretval;
	mod_timer(&vub300->inactivity_timer, jiffies + HZ);
	init_completion(&vub300->irqpoll_complete);
	send_irqpoll(vub300);
	commretval = wait_for_completion_timeout(&vub300->irqpoll_complete,
						 msecs_to_jiffies(500));
	if (vub300->usb_transport_fail) {
		/* no need to do anything */
	} else if (commretval == 0) {
		vub300->usb_timed_out = 1;
		usb_kill_urb(vub300->command_out_urb);
		usb_kill_urb(vub300->command_res_urb);
	} else { /* commretval > 0 */
		__vub300_irqpoll_response(vub300);
	}
}

/* this thread runs only when the driver
 * is trying to poll the device for an IRQ
 */
static void vub300_pollwork_thread(struct work_struct *work)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = container_of(work,
			      struct vub300_mmc_host, pollwork.work);
	if (!vub300->interface) {
		kref_put(&vub300->kref, vub300_delete);
		return;
	}
	mutex_lock(&vub300->cmd_mutex);
	if (vub300->cmd) {
		vub300_queue_poll_work(vub300, 1);
	} else if (!vub300->card_present) {
		/* no need to do anything */
	} else { /* vub300->card_present */
		mutex_lock(&vub300->irq_mutex);
		if (!vub300->irq_enabled) {
			mutex_unlock(&vub300->irq_mutex);
		} else if (vub300->irqs_queued) {
			vub300->irqs_queued -= 1;
			mmc_signal_sdio_irq(vub300->mmc);
			mod_timer(&vub300->inactivity_timer, jiffies + HZ);
			mutex_unlock(&vub300->irq_mutex);
		} else { /* NOT vub300->irqs_queued */
			mutex_unlock(&vub300->irq_mutex);
			__do_poll(vub300);
		}
	}
	mutex_unlock(&vub300->cmd_mutex);
	kref_put(&vub300->kref, vub300_delete);
}

static void vub300_deadwork_thread(struct work_struct *work)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 =
		container_of(work, struct vub300_mmc_host, deadwork);
	if (!vub300->interface) {
		kref_put(&vub300->kref, vub300_delete);
		return;
	}
	mutex_lock(&vub300->cmd_mutex);
	if (vub300->cmd) {
		/*
		 * a command got in as the inactivity
		 * timer expired - so we just let the
		 * processing of the command show if
		 * the device is dead
		 */
	} else if (vub300->card_present) {
		check_vub300_port_status(vub300);
	} else if (vub300->mmc && vub300->mmc->card) {
		/*
		 * the MMC core must not have responded
		 * to the previous indication - lets
		 * hope that it eventually does so we
		 * will just ignore this for now
		 */
	} else {
		check_vub300_port_status(vub300);
	}
	mod_timer(&vub300->inactivity_timer, jiffies + HZ);
	mutex_unlock(&vub300->cmd_mutex);
	kref_put(&vub300->kref, vub300_delete);
}

static void vub300_inactivity_timer_expired(struct timer_list *t)
{				/* softirq */
	struct vub300_mmc_host *vub300 = from_timer(vub300, t,
						    inactivity_timer);
	if (!vub300->interface) {
		kref_put(&vub300->kref, vub300_delete);
	} else if (vub300->cmd) {
		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
	} else {
		vub300_queue_dead_work(vub300);
		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
	}
}

static int vub300_response_error(u8 error_code)
{
	switch (error_code) {
	case SD_ERROR_PIO_TIMEOUT:
	case SD_ERROR_1BIT_TIMEOUT:
	case SD_ERROR_4BIT_TIMEOUT:
		return -ETIMEDOUT;
	case SD_ERROR_STAT_DATA:
	case SD_ERROR_OVERRUN:
	case SD_ERROR_STAT_CMD:
	case SD_ERROR_STAT_CMD_TIMEOUT:
	case SD_ERROR_SDCRDY_STUCK:
	case SD_ERROR_UNHANDLED:
	case SD_ERROR_1BIT_CRC_WRONG:
	case SD_ERROR_4BIT_CRC_WRONG:
	case SD_ERROR_1BIT_CRC_ERROR:
	case SD_ERROR_4BIT_CRC_ERROR:
	case SD_ERROR_NO_CMD_ENDBIT:
	case SD_ERROR_NO_1BIT_DATEND:
	case SD_ERROR_NO_4BIT_DATEND:
	case SD_ERROR_1BIT_DATA_TIMEOUT:
	case SD_ERROR_4BIT_DATA_TIMEOUT:
	case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT:
	case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT:
		return -EILSEQ;
	case 33:
		return -EILSEQ;
	case SD_ERROR_ILLEGAL_COMMAND:
		return -EINVAL;
	case SD_ERROR_NO_DEVICE:
		return -ENOMEDIUM;
	default:
		return -ENODEV;
	}
}

static void command_res_completed(struct urb *urb)
{				/* urb completion handler - hardirq */
	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
	if (urb->status) {
		/* we have to let the initiator handle the error */
	} else if (vub300->command_res_urb->actual_length == 0) {
		/*
		 * we have seen this happen once or twice and
		 * we suspect a buggy USB host controller
		 */
	} else if (!vub300->data) {
		/* this means that the command (typically CMD52) succeeded */
	} else if (vub300->resp.common.header_type != 0x02) {
		/*
		 * this is an error response from the VUB300 chip
		 * and we let the initiator handle it
		 */
	} else if (vub300->urb) {
		vub300->cmd->error =
			vub300_response_error(vub300->resp.error.error_code);
		usb_unlink_urb(vub300->urb);
	} else {
		vub300->cmd->error =
			vub300_response_error(vub300->resp.error.error_code);
		usb_sg_cancel(&vub300->sg_request);
	}
	complete(&vub300->command_complete);	/* got_response_in */
}

static void command_out_completed(struct urb *urb)
{				/* urb completion handler - hardirq */
	struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
	if (urb->status) {
		complete(&vub300->command_complete);
	} else {
		int ret;
		unsigned int pipe =
			usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
		usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
				  &vub300->resp, sizeof(vub300->resp),
				  command_res_completed, vub300);
		vub300->command_res_urb->actual_length = 0;
		ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
		if (ret == 0) {
			/*
			 * the urb completion handler will call
			 * our completion handler
			 */
		} else {
			/*
			 * and thus we only call it directly
			 * when it will not be called
			 */
			complete(&vub300->command_complete);
		}
	}
}

/*
 * the STUFF bits are masked out for the comparisons
 */
static void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300,
					   u32 cmd_arg)
{
	if ((0xFBFFFE00 & cmd_arg) == 0x80022200)
		vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80022000)
		vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80042200)
		vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80042000)
		vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80062200)
		vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80062000)
		vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80082200)
		vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x80082000)
		vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200)
		vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000)
		vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200)
		vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000)
		vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200)
		vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]);
	else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000)
		vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]);
	else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00)
		vub300->bus_width = 1;
	else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02)
		vub300->bus_width = 4;
}

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

/*
 * timer callback runs in atomic mode
 *       so it cannot call usb_kill_urb()
 */
static void vub300_sg_timed_out(struct timer_list *t)
{
	struct vub300_mmc_host *vub300 = from_timer(vub300, t,
						    sg_transfer_timer);
	vub300->usb_timed_out = 1;
	usb_sg_cancel(&vub300->sg_request);
	usb_unlink_urb(vub300->command_out_urb);
	usb_unlink_urb(vub300->command_res_urb);
}

static u16 roundup_to_multiple_of_64(u16 number)
{
	return 0xFFC0 & (0x3F + number);
}

/*
 * this is a separate function to solve the 80 column width restriction
 */
static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
					  const struct firmware *fw)
{
	u8 register_count = 0;
	u16 ts = 0;
	u16 interrupt_size = 0;
	const u8 *data = fw->data;
	int size = fw->size;
	u8 c;
	dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n",
		 vub300->vub_name);
	do {
		c = *data++;
	} while (size-- && c); /* skip comment */
	dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data,
		 vub300->vub_name);
	if (size < 4) {
		dev_err(&vub300->udev->dev,
			"corrupt offload pseudocode in firmware %s\n",
			vub300->vub_name);
		strncpy(vub300->vub_name, "corrupt offload pseudocode",
			sizeof(vub300->vub_name));
		return;
	}
	interrupt_size += *data++;
	size -= 1;
	interrupt_size <<= 8;
	interrupt_size += *data++;
	size -= 1;
	if (interrupt_size < size) {
		u16 xfer_length = roundup_to_multiple_of_64(interrupt_size);
		u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
		if (xfer_buffer) {
			int retval;
			memcpy(xfer_buffer, data, interrupt_size);
			memset(xfer_buffer + interrupt_size, 0,
			       xfer_length - interrupt_size);
			size -= interrupt_size;
			data += interrupt_size;
			retval =
				usb_control_msg(vub300->udev,
						usb_sndctrlpipe(vub300->udev, 0),
						SET_INTERRUPT_PSEUDOCODE,
						USB_DIR_OUT | USB_TYPE_VENDOR |
						USB_RECIP_DEVICE, 0x0000, 0x0000,
						xfer_buffer, xfer_length, HZ);
			kfree(xfer_buffer);
			if (retval < 0)
				goto copy_error_message;
		} else {
			dev_err(&vub300->udev->dev,
				"not enough memory for xfer buffer to send"
				" INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
				vub300->vub_name);
			strncpy(vub300->vub_name,
				"SDIO interrupt pseudocode download failed",
				sizeof(vub300->vub_name));
			return;
		}
	} else {
		dev_err(&vub300->udev->dev,
			"corrupt interrupt pseudocode in firmware %s %s\n",
			fw->data, vub300->vub_name);
		strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
			sizeof(vub300->vub_name));
		return;
	}
	ts += *data++;
	size -= 1;
	ts <<= 8;
	ts += *data++;
	size -= 1;
	if (ts < size) {
		u16 xfer_length = roundup_to_multiple_of_64(ts);
		u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
		if (xfer_buffer) {
			int retval;
			memcpy(xfer_buffer, data, ts);
			memset(xfer_buffer + ts, 0,
			       xfer_length - ts);
			size -= ts;
			data += ts;
			retval =
				usb_control_msg(vub300->udev,
						usb_sndctrlpipe(vub300->udev, 0),
						SET_TRANSFER_PSEUDOCODE,
						USB_DIR_OUT | USB_TYPE_VENDOR |
						USB_RECIP_DEVICE, 0x0000, 0x0000,
						xfer_buffer, xfer_length, HZ);
			kfree(xfer_buffer);
			if (retval < 0)
				goto copy_error_message;
		} else {
			dev_err(&vub300->udev->dev,
				"not enough memory for xfer buffer to send"
				" TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
				vub300->vub_name);
			strncpy(vub300->vub_name,
				"SDIO transfer pseudocode download failed",
				sizeof(vub300->vub_name));
			return;
		}
	} else {
		dev_err(&vub300->udev->dev,
			"corrupt transfer pseudocode in firmware %s %s\n",
			fw->data, vub300->vub_name);
		strncpy(vub300->vub_name, "corrupt transfer pseudocode",
			sizeof(vub300->vub_name));
		return;
	}
	register_count += *data++;
	size -= 1;
	if (register_count * 4 == size) {
		int I = vub300->dynamic_register_count = register_count;
		int i = 0;
		while (I--) {
			unsigned int func_num = 0;
			vub300->sdio_register[i].func_num = *data++;
			size -= 1;
			func_num += *data++;
			size -= 1;
			func_num <<= 8;
			func_num += *data++;
			size -= 1;
			func_num <<= 8;
			func_num += *data++;
			size -= 1;
			vub300->sdio_register[i].sdio_reg = func_num;
			vub300->sdio_register[i].activate = 1;
			vub300->sdio_register[i].prepared = 0;
			i += 1;
		}
		dev_info(&vub300->udev->dev,
			 "initialized %d dynamic pseudocode registers\n",
			 vub300->dynamic_register_count);
		return;
	} else {
		dev_err(&vub300->udev->dev,
			"corrupt dynamic registers in firmware %s\n",
			vub300->vub_name);
		strncpy(vub300->vub_name, "corrupt dynamic registers",
			sizeof(vub300->vub_name));
		return;
	}

	return;

copy_error_message:
	strncpy(vub300->vub_name, "SDIO pseudocode download failed",
		sizeof(vub300->vub_name));
}

/*
 * if the binary containing the EMPTY PseudoCode can not be found
 * vub300->vub_name is set anyway in order to prevent an automatic retry
 */
static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
{
	struct mmc_card *card = vub300->mmc->card;
	int sdio_funcs = card->sdio_funcs;
	const struct firmware *fw = NULL;
	int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name),
			 "vub_%04X%04X", card->cis.vendor, card->cis.device);
	int n = 0;
	int retval;
	for (n = 0; n < sdio_funcs; n++) {
		struct sdio_func *sf = card->sdio_func[n];
		l += snprintf(vub300->vub_name + l,
			      sizeof(vub300->vub_name) - l, "_%04X%04X",
			      sf->vendor, sf->device);
	}
	snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
	dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
		 vub300->vub_name);
	retval = request_firmware(&fw, vub300->vub_name, &card->dev);
	if (retval < 0) {
		strncpy(vub300->vub_name, "vub_default.bin",
			sizeof(vub300->vub_name));
		retval = request_firmware(&fw, vub300->vub_name, &card->dev);
		if (retval < 0) {
			strncpy(vub300->vub_name,
				"no SDIO offload firmware found",
				sizeof(vub300->vub_name));
		} else {
			__download_offload_pseudocode(vub300, fw);
			release_firmware(fw);
		}
	} else {
		__download_offload_pseudocode(vub300, fw);
		release_firmware(fw);
	}
}

static void vub300_usb_bulk_msg_completion(struct urb *urb)
{				/* urb completion handler - hardirq */
	complete((struct completion *)urb->context);
}

static int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300,
			       unsigned int pipe, void *data, int len,
			       int *actual_length, int timeout_msecs)
{
	/* cmd_mutex is held by vub300_cmndwork_thread */
	struct usb_device *usb_dev = vub300->udev;
	struct completion done;
	int retval;
	vub300->urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!vub300->urb)
		return -ENOMEM;
	usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len,
			  vub300_usb_bulk_msg_completion, NULL);
	init_completion(&done);
	vub300->urb->context = &done;
	vub300->urb->actual_length = 0;
	retval = usb_submit_urb(vub300->urb, GFP_KERNEL);
	if (unlikely(retval))
		goto out;
	if (!wait_for_completion_timeout
	    (&done, msecs_to_jiffies(timeout_msecs))) {
		retval = -ETIMEDOUT;
		usb_kill_urb(vub300->urb);
	} else {
		retval = vub300->urb->status;
	}
out:
	*actual_length = vub300->urb->actual_length;
	usb_free_urb(vub300->urb);
	vub300->urb = NULL;
	return retval;
}

static int __command_read_data(struct vub300_mmc_host *vub300,
			       struct mmc_command *cmd, struct mmc_data *data)
{
	/* cmd_mutex is held by vub300_cmndwork_thread */
	int linear_length = vub300->datasize;
	int padded_length = vub300->large_usb_packets ?
		((511 + linear_length) >> 9) << 9 :
		((63 + linear_length) >> 6) << 6;
	if ((padded_length == linear_length) || !pad_input_to_usb_pkt) {
		int result;
		unsigned pipe;
		pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep);
		result = usb_sg_init(&vub300->sg_request, vub300->udev,
				     pipe, 0, data->sg,
				     data->sg_len, 0, GFP_KERNEL);
		if (result < 0) {
			usb_unlink_urb(vub300->command_out_urb);
			usb_unlink_urb(vub300->command_res_urb);
			cmd->error = result;
			data->bytes_xfered = 0;
			return 0;
		} else {
			vub300->sg_transfer_timer.expires =
				jiffies + msecs_to_jiffies(2000 +
						  (linear_length / 16384));
			add_timer(&vub300->sg_transfer_timer);
			usb_sg_wait(&vub300->sg_request);
			del_timer(&vub300->sg_transfer_timer);
			if (vub300->sg_request.status < 0) {
				cmd->error = vub300->sg_request.status;
				data->bytes_xfered = 0;
				return 0;
			} else {
				data->bytes_xfered = vub300->datasize;
				return linear_length;
			}
		}
	} else {
		u8 *buf = kmalloc(padded_length, GFP_KERNEL);
		if (buf) {
			int result;
			unsigned pipe = usb_rcvbulkpipe(vub300->udev,
							vub300->data_inp_ep);
			int actual_length = 0;
			result = vub300_usb_bulk_msg(vub300, pipe, buf,
					     padded_length, &actual_length,
					     2000 + (padded_length / 16384));
			if (result < 0) {
				cmd->error = result;
				data->bytes_xfered = 0;
				kfree(buf);
				return 0;
			} else if (actual_length < linear_length) {
				cmd->error = -EREMOTEIO;
				data->bytes_xfered = 0;
				kfree(buf);
				return 0;
			} else {
				sg_copy_from_buffer(data->sg, data->sg_len, buf,
						    linear_length);
				kfree(buf);
				data->bytes_xfered = vub300->datasize;
				return linear_length;
			}
		} else {
			cmd->error = -ENOMEM;
			data->bytes_xfered = 0;
			return 0;
		}
	}
}

static int __command_write_data(struct vub300_mmc_host *vub300,
				struct mmc_command *cmd, struct mmc_data *data)
{
	/* cmd_mutex is held by vub300_cmndwork_thread */
	unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep);
	int linear_length = vub300->datasize;
	int modulo_64_length = linear_length & 0x003F;
	int modulo_512_length = linear_length & 0x01FF;
	if (linear_length < 64) {
		int result;
		int actual_length;
		sg_copy_to_buffer(data->sg, data->sg_len,
				  vub300->padded_buffer,
				  sizeof(vub300->padded_buffer));
		memset(vub300->padded_buffer + linear_length, 0,
		       sizeof(vub300->padded_buffer) - linear_length);
		result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer,
					     sizeof(vub300->padded_buffer),
					     &actual_length, 2000 +
					     (sizeof(vub300->padded_buffer) /
					      16384));
		if (result < 0) {
			cmd->error = result;
			data->bytes_xfered = 0;
		} else {
			data->bytes_xfered = vub300->datasize;
		}
	} else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) ||
		    (vub300->large_usb_packets && (64 > modulo_512_length))
		) {		/* don't you just love these work-rounds */
		int padded_length = ((63 + linear_length) >> 6) << 6;
		u8 *buf = kmalloc(padded_length, GFP_KERNEL);
		if (buf) {
			int result;
			int actual_length;
			sg_copy_to_buffer(data->sg, data->sg_len, buf,
					  padded_length);
			memset(buf + linear_length, 0,
			       padded_length - linear_length);
			result =
				vub300_usb_bulk_msg(vub300, pipe, buf,
						    padded_length, &actual_length,
						    2000 + padded_length / 16384);
			kfree(buf);
			if (result < 0) {
				cmd->error = result;
				data->bytes_xfered = 0;
			} else {
				data->bytes_xfered = vub300->datasize;
			}
		} else {
			cmd->error = -ENOMEM;
			data->bytes_xfered = 0;
		}
	} else {		/* no data padding required */
		int result;
		unsigned char buf[64 * 4];
		sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf));
		result = usb_sg_init(&vub300->sg_request, vub300->udev,
				     pipe, 0, data->sg,
				     data->sg_len, 0, GFP_KERNEL);
		if (result < 0) {
			usb_unlink_urb(vub300->command_out_urb);
			usb_unlink_urb(vub300->command_res_urb);
			cmd->error = result;
			data->bytes_xfered = 0;
		} else {
			vub300->sg_transfer_timer.expires =
				jiffies + msecs_to_jiffies(2000 +
							   linear_length / 16384);
			add_timer(&vub300->sg_transfer_timer);
			usb_sg_wait(&vub300->sg_request);
			if (cmd->error) {
				data->bytes_xfered = 0;
			} else {
				del_timer(&vub300->sg_transfer_timer);
				if (vub300->sg_request.status < 0) {
					cmd->error = vub300->sg_request.status;
					data->bytes_xfered = 0;
				} else {
					data->bytes_xfered = vub300->datasize;
				}
			}
		}
	}
	return linear_length;
}

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

static void construct_request_response(struct vub300_mmc_host *vub300,
				       struct mmc_command *cmd)
{
	int resp_len = vub300->resp_len;
	int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1;
	int bytes = 3 & less_cmd;
	int words = less_cmd >> 2;
	u8 *r = vub300->resp.response.command_response;
	if (bytes == 3) {
		cmd->resp[words] = (r[1 + (words << 2)] << 24)
			| (r[2 + (words << 2)] << 16)
			| (r[3 + (words << 2)] << 8);
	} else if (bytes == 2) {
		cmd->resp[words] = (r[1 + (words << 2)] << 24)
			| (r[2 + (words << 2)] << 16);
	} else if (bytes == 1) {
		cmd->resp[words] = (r[1 + (words << 2)] << 24);
	}
	while (words-- > 0) {
		cmd->resp[words] = (r[1 + (words << 2)] << 24)
			| (r[2 + (words << 2)] << 16)
			| (r[3 + (words << 2)] << 8)
			| (r[4 + (words << 2)] << 0);
	}
	if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0]))
		cmd->resp[0] &= 0xFFFFFF00;
}

/* this thread runs only when there is an upper level command req outstanding */
static void vub300_cmndwork_thread(struct work_struct *work)
{
	struct vub300_mmc_host *vub300 =
		container_of(work, struct vub300_mmc_host, cmndwork);
	if (!vub300->interface) {
		kref_put(&vub300->kref, vub300_delete);
		return;
	} else {
		struct mmc_request *req = vub300->req;
		struct mmc_command *cmd = vub300->cmd;
		struct mmc_data *data = vub300->data;
		int data_length;
		mutex_lock(&vub300->cmd_mutex);
		init_completion(&vub300->command_complete);
		if (likely(vub300->vub_name[0]) || !vub300->mmc->card) {
			/*
			 * the name of the EMPTY Pseudo firmware file
			 * is used as a flag to indicate that the file
			 * has been already downloaded to the VUB300 chip
			 */
		} else if (0 == vub300->mmc->card->sdio_funcs) {
			strncpy(vub300->vub_name, "SD memory device",
				sizeof(vub300->vub_name));
		} else {
			download_offload_pseudocode(vub300);
		}
		send_command(vub300);
		if (!data)
			data_length = 0;
		else if (MMC_DATA_READ & data->flags)
			data_length = __command_read_data(vub300, cmd, data);
		else
			data_length = __command_write_data(vub300, cmd, data);
		__vub300_command_response(vub300, cmd, data, data_length);
		vub300->req = NULL;
		vub300->cmd = NULL;
		vub300->data = NULL;
		if (cmd->error) {
			if (cmd->error == -ENOMEDIUM)
				check_vub300_port_status(vub300);
			mutex_unlock(&vub300->cmd_mutex);
			mmc_request_done(vub300->mmc, req);
			kref_put(&vub300->kref, vub300_delete);
			return;
		} else {
			construct_request_response(vub300, cmd);
			vub300->resp_len = 0;
			mutex_unlock(&vub300->cmd_mutex);
			kref_put(&vub300->kref, vub300_delete);
			mmc_request_done(vub300->mmc, req);
			return;
		}
	}
}

static int examine_cyclic_buffer(struct vub300_mmc_host *vub300,
				 struct mmc_command *cmd, u8 Function)
{
	/* cmd_mutex is held by vub300_mmc_request */
	u8 cmd0 = 0xFF & (cmd->arg >> 24);
	u8 cmd1 = 0xFF & (cmd->arg >> 16);
	u8 cmd2 = 0xFF & (cmd->arg >> 8);
	u8 cmd3 = 0xFF & (cmd->arg >> 0);
	int first = MAXREGMASK & vub300->fn[Function].offload_point;
	struct offload_registers_access *rf = &vub300->fn[Function].reg[first];
	if (cmd0 == rf->command_byte[0] &&
	    cmd1 == rf->command_byte[1] &&
	    cmd2 == rf->command_byte[2] &&
	    cmd3 == rf->command_byte[3]) {
		u8 checksum = 0x00;
		cmd->resp[1] = checksum << 24;
		cmd->resp[0] = (rf->Respond_Byte[0] << 24)
			| (rf->Respond_Byte[1] << 16)
			| (rf->Respond_Byte[2] << 8)
			| (rf->Respond_Byte[3] << 0);
		vub300->fn[Function].offload_point += 1;
		vub300->fn[Function].offload_count -= 1;
		vub300->total_offload_count -= 1;
		return 1;
	} else {
		int delta = 1;	/* because it does not match the first one */
		u8 register_count = vub300->fn[Function].offload_count - 1;
		u32 register_point = vub300->fn[Function].offload_point + 1;
		while (0 < register_count) {
			int point = MAXREGMASK & register_point;
			struct offload_registers_access *r =
				&vub300->fn[Function].reg[point];
			if (cmd0 == r->command_byte[0] &&
			    cmd1 == r->command_byte[1] &&
			    cmd2 == r->command_byte[2] &&
			    cmd3 == r->command_byte[3]) {
				u8 checksum = 0x00;
				cmd->resp[1] = checksum << 24;
				cmd->resp[0] = (r->Respond_Byte[0] << 24)
					| (r->Respond_Byte[1] << 16)
					| (r->Respond_Byte[2] << 8)
					| (r->Respond_Byte[3] << 0);
				vub300->fn[Function].offload_point += delta;
				vub300->fn[Function].offload_count -= delta;
				vub300->total_offload_count -= delta;
				return 1;
			} else {
				register_point += 1;
				register_count -= 1;
				delta += 1;
				continue;
			}
		}
		return 0;
	}
}

static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
					       struct mmc_command *cmd)
{
	/* cmd_mutex is held by vub300_mmc_request */
	u8 regs = vub300->dynamic_register_count;
	u8 i = 0;
	u8 func = FUN(cmd);
	u32 reg = REG(cmd);
	while (0 < regs--) {
		if ((vub300->sdio_register[i].func_num == func) &&
		    (vub300->sdio_register[i].sdio_reg == reg)) {
			if (!vub300->sdio_register[i].prepared) {
				return 0;
			} else if ((0x80000000 & cmd->arg) == 0x80000000) {
				/*
				 * a write to a dynamic register
				 * nullifies our offloaded value
				 */
				vub300->sdio_register[i].prepared = 0;
				return 0;
			} else {
				u8 checksum = 0x00;
				u8 rsp0 = 0x00;
				u8 rsp1 = 0x00;
				u8 rsp2 = vub300->sdio_register[i].response;
				u8 rsp3 = vub300->sdio_register[i].regvalue;
				vub300->sdio_register[i].prepared = 0;
				cmd->resp[1] = checksum << 24;
				cmd->resp[0] = (rsp0 << 24)
					| (rsp1 << 16)
					| (rsp2 << 8)
					| (rsp3 << 0);
				return 1;
			}
		} else {
			i += 1;
			continue;
		}
	}
	if (vub300->total_offload_count == 0)
		return 0;
	else if (vub300->fn[func].offload_count == 0)
		return 0;
	else
		return examine_cyclic_buffer(vub300, cmd, func);
}

static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
{				/* NOT irq */
	struct mmc_command *cmd = req->cmd;
	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
	if (!vub300->interface) {
		cmd->error = -ESHUTDOWN;
		mmc_request_done(mmc, req);
		return;
	} else {
		struct mmc_data *data = req->data;
		if (!vub300->card_powered) {
			cmd->error = -ENOMEDIUM;
			mmc_request_done(mmc, req);
			return;
		}
		if (!vub300->card_present) {
			cmd->error = -ENOMEDIUM;
			mmc_request_done(mmc, req);
			return;
		}
		if (vub300->usb_transport_fail) {
			cmd->error = vub300->usb_transport_fail;
			mmc_request_done(mmc, req);
			return;
		}
		if (!vub300->interface) {
			cmd->error = -ENODEV;
			mmc_request_done(mmc, req);
			return;
		}
		kref_get(&vub300->kref);
		mutex_lock(&vub300->cmd_mutex);
		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
		/*
		 * for performance we have to return immediately
		 * if the requested data has been offloaded
		 */
		if (cmd->opcode == 52 &&
		    satisfy_request_from_offloaded_data(vub300, cmd)) {
			cmd->error = 0;
			mutex_unlock(&vub300->cmd_mutex);
			kref_put(&vub300->kref, vub300_delete);
			mmc_request_done(mmc, req);
			return;
		} else {
			vub300->cmd = cmd;
			vub300->req = req;
			vub300->data = data;
			if (data)
				vub300->datasize = data->blksz * data->blocks;
			else
				vub300->datasize = 0;
			vub300_queue_cmnd_work(vub300);
			mutex_unlock(&vub300->cmd_mutex);
			kref_put(&vub300->kref, vub300_delete);
			/*
			 * the kernel lock diagnostics complain
			 * if the cmd_mutex * is "passed on"
			 * to the cmndwork thread,
			 * so we must release it now
			 * and re-acquire it in the cmndwork thread
			 */
		}
	}
}

static void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8],
			      struct mmc_ios *ios)
{
	int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */
	int retval;
	u32 kHzClock;
	if (ios->clock >= 48000000)
		kHzClock = 48000;
	else if (ios->clock >= 24000000)
		kHzClock = 24000;
	else if (ios->clock >= 20000000)
		kHzClock = 20000;
	else if (ios->clock >= 15000000)
		kHzClock = 15000;
	else if (ios->clock >= 200000)
		kHzClock = 200;
	else
		kHzClock = 0;
	{
		int i;
		u64 c = kHzClock;
		for (i = 0; i < buf_array_size; i++) {
			buf[i] = c;
			c >>= 8;
		}
	}
	retval =
		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
				SET_CLOCK_SPEED,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				0x00, 0x00, buf, buf_array_size, HZ);
	if (retval != 8) {
		dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
			" %dkHz failed with retval=%d\n", kHzClock, retval);
	} else {
		dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED"
			" %dkHz\n", kHzClock);
	}
}

static void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
	if (!vub300->interface)
		return;
	kref_get(&vub300->kref);
	mutex_lock(&vub300->cmd_mutex);
	if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) {
		vub300->card_powered = 0;
		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
				SET_SD_POWER,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				0x0000, 0x0000, NULL, 0, HZ);
		/* must wait for the VUB300 u-proc to boot up */
		msleep(600);
	} else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
				SET_SD_POWER,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				0x0001, 0x0000, NULL, 0, HZ);
		msleep(600);
		vub300->card_powered = 1;
	} else if (ios->power_mode == MMC_POWER_ON) {
		u8 *buf = kmalloc(8, GFP_KERNEL);
		if (buf) {
			__set_clock_speed(vub300, buf, ios);
			kfree(buf);
		}
	} else {
		/* this should mean no change of state */
	}
	mutex_unlock(&vub300->cmd_mutex);
	kref_put(&vub300->kref, vub300_delete);
}

static int vub300_mmc_get_ro(struct mmc_host *mmc)
{
	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
	return vub300->read_only;
}

static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
	if (!vub300->interface)
		return;
	kref_get(&vub300->kref);
	if (enable) {
		mutex_lock(&vub300->irq_mutex);
		if (vub300->irqs_queued) {
			vub300->irqs_queued -= 1;
			mmc_signal_sdio_irq(vub300->mmc);
		} else if (vub300->irq_disabled) {
			vub300->irq_disabled = 0;
			vub300->irq_enabled = 1;
			vub300_queue_poll_work(vub300, 0);
		} else if (vub300->irq_enabled) {
			/* this should not happen, so we will just ignore it */
		} else {
			vub300->irq_enabled = 1;
			vub300_queue_poll_work(vub300, 0);
		}
		mutex_unlock(&vub300->irq_mutex);
	} else {
		vub300->irq_enabled = 0;
	}
	kref_put(&vub300->kref, vub300_delete);
}

static void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = mmc_priv(mmc);
	dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
}

static const struct mmc_host_ops vub300_mmc_ops = {
	.request = vub300_mmc_request,
	.set_ios = vub300_mmc_set_ios,
	.get_ro = vub300_mmc_get_ro,
	.enable_sdio_irq = vub300_enable_sdio_irq,
	.init_card = vub300_init_card,
};

static int vub300_probe(struct usb_interface *interface,
			const struct usb_device_id *id)
{				/* NOT irq */
	struct vub300_mmc_host *vub300;
	struct usb_host_interface *iface_desc;
	struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
	int i;
	int retval = -ENOMEM;
	struct urb *command_out_urb;
	struct urb *command_res_urb;
	struct mmc_host *mmc;
	char manufacturer[48];
	char product[32];
	char serial_number[32];
	usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
		   sizeof(manufacturer));
	usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
	usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
		   sizeof(serial_number));
	dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
		 le16_to_cpu(udev->descriptor.idVendor),
		 le16_to_cpu(udev->descriptor.idProduct),
		 manufacturer, product, serial_number);
	command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!command_out_urb) {
		retval = -ENOMEM;
		goto error0;
	}
	command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!command_res_urb) {
		retval = -ENOMEM;
		goto error1;
	}
	/* this also allocates memory for our VUB300 mmc host device */
	mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
	if (!mmc) {
		retval = -ENOMEM;
		dev_err(&udev->dev, "not enough memory for the mmc_host\n");
		goto error4;
	}
	/* MMC core transfer sizes tunable parameters */
	mmc->caps = 0;
	if (!force_1_bit_data_xfers)
		mmc->caps |= MMC_CAP_4_BIT_DATA;
	if (!force_polling_for_irqs)
		mmc->caps |= MMC_CAP_SDIO_IRQ;
	mmc->caps &= ~MMC_CAP_NEEDS_POLL;
	/*
	 * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
	 * for devices which results in spurious CMD7's being
	 * issued which stops some SDIO cards from working
	 */
	if (limit_speed_to_24_MHz) {
		mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
		mmc->f_max = 24000000;
		dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
	} else {
		mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
		mmc->f_max = 48000000;
	}
	mmc->f_min = 200000;
	mmc->max_blk_count = 511;
	mmc->max_blk_size = 512;
	mmc->max_segs = 128;
	if (force_max_req_size)
		mmc->max_req_size = force_max_req_size * 1024;
	else
		mmc->max_req_size = 64 * 1024;
	mmc->max_seg_size = mmc->max_req_size;
	mmc->ocr_avail = 0;
	mmc->ocr_avail |= MMC_VDD_165_195;
	mmc->ocr_avail |= MMC_VDD_20_21;
	mmc->ocr_avail |= MMC_VDD_21_22;
	mmc->ocr_avail |= MMC_VDD_22_23;
	mmc->ocr_avail |= MMC_VDD_23_24;
	mmc->ocr_avail |= MMC_VDD_24_25;
	mmc->ocr_avail |= MMC_VDD_25_26;
	mmc->ocr_avail |= MMC_VDD_26_27;
	mmc->ocr_avail |= MMC_VDD_27_28;
	mmc->ocr_avail |= MMC_VDD_28_29;
	mmc->ocr_avail |= MMC_VDD_29_30;
	mmc->ocr_avail |= MMC_VDD_30_31;
	mmc->ocr_avail |= MMC_VDD_31_32;
	mmc->ocr_avail |= MMC_VDD_32_33;
	mmc->ocr_avail |= MMC_VDD_33_34;
	mmc->ocr_avail |= MMC_VDD_34_35;
	mmc->ocr_avail |= MMC_VDD_35_36;
	mmc->ops = &vub300_mmc_ops;
	vub300 = mmc_priv(mmc);
	vub300->mmc = mmc;
	vub300->card_powered = 0;
	vub300->bus_width = 0;
	vub300->cmnd.head.block_size[0] = 0x00;
	vub300->cmnd.head.block_size[1] = 0x00;
	vub300->app_spec = 0;
	mutex_init(&vub300->cmd_mutex);
	mutex_init(&vub300->irq_mutex);
	vub300->command_out_urb = command_out_urb;
	vub300->command_res_urb = command_res_urb;
	vub300->usb_timed_out = 0;
	vub300->dynamic_register_count = 0;

	for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
		vub300->fn[i].offload_point = 0;
		vub300->fn[i].offload_count = 0;
	}

	vub300->total_offload_count = 0;
	vub300->irq_enabled = 0;
	vub300->irq_disabled = 0;
	vub300->irqs_queued = 0;

	for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
		vub300->sdio_register[i++].activate = 0;

	vub300->udev = udev;
	vub300->interface = interface;
	vub300->cmnd_res_ep = 0;
	vub300->cmnd_out_ep = 0;
	vub300->data_inp_ep = 0;
	vub300->data_out_ep = 0;

	for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
		vub300->fbs[i] = 512;

	/*
	 *      set up the endpoint information
	 *
	 * use the first pair of bulk-in and bulk-out
	 *     endpoints for Command/Response+Interrupt
	 *
	 * use the second pair of bulk-in and bulk-out
	 *     endpoints for Data In/Out
	 */
	vub300->large_usb_packets = 0;
	iface_desc = interface->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		struct usb_endpoint_descriptor *endpoint =
			&iface_desc->endpoint[i].desc;
		dev_info(&vub300->udev->dev,
			 "vub300 testing %s EndPoint(%d) %02X\n",
			 usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
			 usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
			 "UNKNOWN", i, endpoint->bEndpointAddress);
		if (endpoint->wMaxPacketSize > 64)
			vub300->large_usb_packets = 1;
		if (usb_endpoint_is_bulk_in(endpoint)) {
			if (!vub300->cmnd_res_ep) {
				vub300->cmnd_res_ep =
					endpoint->bEndpointAddress;
			} else if (!vub300->data_inp_ep) {
				vub300->data_inp_ep =
					endpoint->bEndpointAddress;
			} else {
				dev_warn(&vub300->udev->dev,
					 "ignoring"
					 " unexpected bulk_in endpoint");
			}
		} else if (usb_endpoint_is_bulk_out(endpoint)) {
			if (!vub300->cmnd_out_ep) {
				vub300->cmnd_out_ep =
					endpoint->bEndpointAddress;
			} else if (!vub300->data_out_ep) {
				vub300->data_out_ep =
					endpoint->bEndpointAddress;
			} else {
				dev_warn(&vub300->udev->dev,
					 "ignoring"
					 " unexpected bulk_out endpoint");
			}
		} else {
			dev_warn(&vub300->udev->dev,
				 "vub300 ignoring EndPoint(%d) %02X", i,
				 endpoint->bEndpointAddress);
		}
	}
	if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
	    vub300->data_inp_ep && vub300->data_out_ep) {
		dev_info(&vub300->udev->dev,
			 "vub300 %s packets"
			 " using EndPoints %02X %02X %02X %02X\n",
			 vub300->large_usb_packets ? "LARGE" : "SMALL",
			 vub300->cmnd_out_ep, vub300->cmnd_res_ep,
			 vub300->data_out_ep, vub300->data_inp_ep);
		/* we have the expected EndPoints */
	} else {
		dev_err(&vub300->udev->dev,
		    "Could not find two sets of bulk-in/out endpoint pairs\n");
		retval = -EINVAL;
		goto error5;
	}
	retval =
		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
				GET_HC_INF0,
				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				0x0000, 0x0000, &vub300->hc_info,
				sizeof(vub300->hc_info), HZ);
	if (retval < 0)
		goto error5;
	retval =
		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
				SET_ROM_WAIT_STATES,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
	if (retval < 0)
		goto error5;
	dev_info(&vub300->udev->dev,
		 "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
		 (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
		 (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
		 mmc->f_max / 1000000,
		 pad_input_to_usb_pkt ? "padding input data to" : "with",
		 vub300->large_usb_packets ? 512 : 64);
	retval =
		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
				GET_SYSTEM_PORT_STATUS,
				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				0x0000, 0x0000, &vub300->system_port_status,
				sizeof(vub300->system_port_status), HZ);
	if (retval < 0) {
		goto error4;
	} else if (sizeof(vub300->system_port_status) == retval) {
		vub300->card_present =
			(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
		vub300->read_only =
			(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
	} else {
		goto error4;
	}
	usb_set_intfdata(interface, vub300);
	INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
	INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
	INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
	kref_init(&vub300->kref);
	timer_setup(&vub300->sg_transfer_timer, vub300_sg_timed_out, 0);
	kref_get(&vub300->kref);
	timer_setup(&vub300->inactivity_timer,
		    vub300_inactivity_timer_expired, 0);
	vub300->inactivity_timer.expires = jiffies + HZ;
	add_timer(&vub300->inactivity_timer);
	if (vub300->card_present)
		dev_info(&vub300->udev->dev,
			 "USB vub300 remote SDIO host controller[%d]"
			 "connected with SD/SDIO card inserted\n",
			 interface_to_InterfaceNumber(interface));
	else
		dev_info(&vub300->udev->dev,
			 "USB vub300 remote SDIO host controller[%d]"
			 "connected with no SD/SDIO card inserted\n",
			 interface_to_InterfaceNumber(interface));
	mmc_add_host(mmc);
	return 0;
error5:
	mmc_free_host(mmc);
	/*
	 * and hence also frees vub300
	 * which is contained at the end of struct mmc
	 */
error4:
	usb_free_urb(command_res_urb);
error1:
	usb_free_urb(command_out_urb);
error0:
	usb_put_dev(udev);
	return retval;
}

static void vub300_disconnect(struct usb_interface *interface)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = usb_get_intfdata(interface);
	if (!vub300 || !vub300->mmc) {
		return;
	} else {
		struct mmc_host *mmc = vub300->mmc;
		if (!vub300->mmc) {
			return;
		} else {
			int ifnum = interface_to_InterfaceNumber(interface);
			usb_set_intfdata(interface, NULL);
			/* prevent more I/O from starting */
			vub300->interface = NULL;
			kref_put(&vub300->kref, vub300_delete);
			mmc_remove_host(mmc);
			pr_info("USB vub300 remote SDIO host controller[%d]"
				" now disconnected", ifnum);
			return;
		}
	}
}

#ifdef CONFIG_PM
static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
{
	return 0;
}

static int vub300_resume(struct usb_interface *intf)
{
	return 0;
}
#else
#define vub300_suspend NULL
#define vub300_resume NULL
#endif
static int vub300_pre_reset(struct usb_interface *intf)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
	mutex_lock(&vub300->cmd_mutex);
	return 0;
}

static int vub300_post_reset(struct usb_interface *intf)
{				/* NOT irq */
	struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
	/* we are sure no URBs are active - no locking needed */
	vub300->errors = -EPIPE;
	mutex_unlock(&vub300->cmd_mutex);
	return 0;
}

static struct usb_driver vub300_driver = {
	.name = "vub300",
	.probe = vub300_probe,
	.disconnect = vub300_disconnect,
	.suspend = vub300_suspend,
	.resume = vub300_resume,
	.pre_reset = vub300_pre_reset,
	.post_reset = vub300_post_reset,
	.id_table = vub300_table,
	.supports_autosuspend = 1,
};

static int __init vub300_init(void)
{				/* NOT irq */
	int result;

	pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X",
		firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout);
	cmndworkqueue = create_singlethread_workqueue("kvub300c");
	if (!cmndworkqueue) {
		pr_err("not enough memory for the REQUEST workqueue");
		result = -ENOMEM;
		goto out1;
	}
	pollworkqueue = create_singlethread_workqueue("kvub300p");
	if (!pollworkqueue) {
		pr_err("not enough memory for the IRQPOLL workqueue");
		result = -ENOMEM;
		goto out2;
	}
	deadworkqueue = create_singlethread_workqueue("kvub300d");
	if (!deadworkqueue) {
		pr_err("not enough memory for the EXPIRED workqueue");
		result = -ENOMEM;
		goto out3;
	}
	result = usb_register(&vub300_driver);
	if (result) {
		pr_err("usb_register failed. Error number %d", result);
		goto out4;
	}
	return 0;
out4:
	destroy_workqueue(deadworkqueue);
out3:
	destroy_workqueue(pollworkqueue);
out2:
	destroy_workqueue(cmndworkqueue);
out1:
	return result;
}

static void __exit vub300_exit(void)
{
	usb_deregister(&vub300_driver);
	flush_workqueue(cmndworkqueue);
	flush_workqueue(pollworkqueue);
	flush_workqueue(deadworkqueue);
	destroy_workqueue(cmndworkqueue);
	destroy_workqueue(pollworkqueue);
	destroy_workqueue(deadworkqueue);
}

module_init(vub300_init);
module_exit(vub300_exit);

MODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>");
MODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver");
MODULE_LICENSE("GPL");