// SPDX-License-Identifier: GPL-2.0-only
/*
* 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 )
*
* 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 128 x48 - 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[];
} __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 0 x01
#define RESPONSE_ERROR 0 x02
#define RESPONSE_STATUS 0 x03
#define RESPONSE_IRQ_DISABLED 0 x05
#define RESPONSE_IRQ_ENABLED 0 x06
#define RESPONSE_PIGGYBACKED 0 x07
#define RESPONSE_NO_INTERRUPT 0 x08
#define RESPONSE_PIG_DISABLED 0 x09
#define RESPONSE_PIG_ENABLED 0 x0A
#define SD_ERROR_1BIT_TIMEOUT 0 x01
#define SD_ERROR_4BIT_TIMEOUT 0 x02
#define SD_ERROR_1BIT_CRC_WRONG 0 x03
#define SD_ERROR_4BIT_CRC_WRONG 0 x04
#define SD_ERROR_1BIT_CRC_ERROR 0 x05
#define SD_ERROR_4BIT_CRC_ERROR 0 x06
#define SD_ERROR_NO_CMD_ENDBIT 0 x07
#define SD_ERROR_NO_1BIT_DATEND 0 x08
#define SD_ERROR_NO_4BIT_DATEND 0 x09
#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT 0 x0A
#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT 0 x0B
#define SD_ERROR_ILLEGAL_COMMAND 0 x0C
#define SD_ERROR_NO_DEVICE 0 x0D
#define SD_ERROR_TRANSFER_LENGTH 0 x0E
#define SD_ERROR_1BIT_DATA_TIMEOUT 0 x0F
#define SD_ERROR_4BIT_DATA_TIMEOUT 0 x10
#define SD_ERROR_ILLEGAL_STATE 0 x11
#define SD_ERROR_UNKNOWN_ERROR 0 x12
#define SD_ERROR_RESERVED_ERROR 0 x13
#define SD_ERROR_INVALID_FUNCTION 0 x14
#define SD_ERROR_OUT_OF_RANGE 0 x15
#define SD_ERROR_STAT_CMD 0 x16
#define SD_ERROR_STAT_DATA 0 x17
#define SD_ERROR_STAT_CMD_TIMEOUT 0 x18
#define SD_ERROR_SDCRDY_STUCK 0 x19
#define SD_ERROR_UNHANDLED 0 x1A
#define SD_ERROR_OVERRUN 0 x1B
#define SD_ERROR_PIO_TIMEOUT 0 x1C
#define FUN(c) (0 x000007 & (c->arg>>28 ))
#define REG(c) (0 x01FFFF & (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 = 0 x04;
#else
static int firmware_rom_wait_states = 0 x1C;
#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 0 x2201
#define VUB300_VENDOR_ID 0 x0424
#define VUB300_PRODUCT_ID 0 x012C
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);
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);
/*
* 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 = 0 xFFFF & (0 x0001FFFF - 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 = 0 xFF & (unsigned )timeout;
vub300->cmnd.poll.poll_timeout_msb = 0 xFF & (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 =
(0 x0001 & vub300->system_port_status.port_flags) ? 1 : 0 ;
vub300->read_only =
(0 x0010 & 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)
strscpy(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 = ((0 x03 & register_access->command_byte[0 ]) << 15 )
| ((0 xFF & register_access->command_byte[1 ]) << 7 )
| ((0 xFE & register_access->command_byte[2 ]) >> 1 );
u8 func = ((0 x70 & 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,
0 x0000, 0 x0000, &vub300->system_port_status,
sizeof (vub300->system_port_status), 1000 );
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 = timer_container_of(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 != 0 x02) {
/*
* 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 ((0 xFBFFFE00 & cmd_arg) == 0 x80022200)
vub300->fbs[1 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[1 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80022000)
vub300->fbs[1 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[1 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80042200)
vub300->fbs[2 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[2 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80042000)
vub300->fbs[2 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[2 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80062200)
vub300->fbs[3 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[3 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80062000)
vub300->fbs[3 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[3 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80082200)
vub300->fbs[4 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[4 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x80082000)
vub300->fbs[4 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[4 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x800A2200)
vub300->fbs[5 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[5 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x800A2000)
vub300->fbs[5 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[5 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x800C2200)
vub300->fbs[6 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[6 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x800C2000)
vub300->fbs[6 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[6 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x800E2200)
vub300->fbs[7 ] = (cmd_arg << 8 ) | (0 x00FF & vub300->fbs[7 ]);
else if ((0 xFBFFFE00 & cmd_arg) == 0 x800E2000)
vub300->fbs[7 ] = (0 xFF & cmd_arg) | (0 xFF00 & vub300->fbs[7 ]);
else if ((0 xFBFFFE03 & cmd_arg) == 0 x80000E00)
vub300->bus_width = 1 ;
else if ((0 xFBFFFE03 & cmd_arg) == 0 x80000E02)
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 (0 x00000000 == (0 x00000003 & cmd->arg))
vub300->bus_width = 1 ;
else if (0 x00000002 == (0 x00000003 & cmd->arg))
vub300->bus_width = 4 ;
else
dev_err(&vub300->udev->dev,
"unexpected ACMD6 bus_width=%d\n" ,
0 x00000003 & 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] = 0 xFFFF & 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 = 0 x00;
vub300->cmnd.head.port_number = 0 ; /* "0" means port 1 */
vub300->cmnd.head.command_type = 0 x00; /* 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 = 0 x7 & (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 ) & 0 xFF;
vub300->cmnd.head.block_size[1 ] = (vub300->fbs[fn] >> 0 ) & 0 xFF;
vub300->cmnd.head.command_type = 0 x00;
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 ) & 0 xFF;
vub300->cmnd.head.block_size[1 ] = (vub300->fbs[0 ] >> 0 ) & 0 xFF;
vub300->cmnd.head.command_type = 0 x00;
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 = 0 x7 & (cmd->arg >> 28 );
if (0 x08 & vub300->cmnd.head.arguments[0 ]) { /* BLOCK MODE */
vub300->cmnd.head.block_count[0 ] =
(data->blocks >> 8 ) & 0 xFF;
vub300->cmnd.head.block_count[1 ] =
(data->blocks >> 0 ) & 0 xFF;
vub300->cmnd.head.block_size[0 ] =
(data->blksz >> 8 ) & 0 xFF;
vub300->cmnd.head.block_size[1 ] =
(data->blksz >> 0 ) & 0 xFF;
} 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 ) & 0 xFF;
vub300->cmnd.head.block_size[1 ] =
(vub300->datasize >> 0 ) & 0 xFF;
}
vub300->cmnd.head.command_type =
(MMC_DATA_READ & data->flags) ? 0 x00 : 0 x80;
vub300->cmnd.head.transfer_size[0 ] =
(vub300->datasize >> 24 ) & 0 xFF;
vub300->cmnd.head.transfer_size[1 ] =
(vub300->datasize >> 16 ) & 0 xFF;
vub300->cmnd.head.transfer_size[2 ] =
(vub300->datasize >> 8 ) & 0 xFF;
vub300->cmnd.head.transfer_size[3 ] =
(vub300->datasize >> 0 ) & 0 xFF;
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 ) & 0 xFF;
vub300->cmnd.head.block_count[1 ] = (data->blocks >> 0 ) & 0 xFF;
vub300->cmnd.head.block_size[0 ] = (data->blksz >> 8 ) & 0 xFF;
vub300->cmnd.head.block_size[1 ] = (data->blksz >> 0 ) & 0 xFF;
vub300->cmnd.head.command_type =
(MMC_DATA_READ & data->flags) ? 0 x00 : 0 x80;
vub300->cmnd.head.transfer_size[0 ] =
(vub300->datasize >> 24 ) & 0 xFF;
vub300->cmnd.head.transfer_size[1 ] =
(vub300->datasize >> 16 ) & 0 xFF;
vub300->cmnd.head.transfer_size[2 ] =
(vub300->datasize >> 8 ) & 0 xFF;
vub300->cmnd.head.transfer_size[3 ] =
(vub300->datasize >> 0 ) & 0 xFF;
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 ) & 0 xFF;
vub300->cmnd.head.block_boundary[1 ] =
(block_boundary >> 0 ) & 0 xFF;
} 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 = timer_container_of(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 0 xFFC0 & (0 x3F + 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);
strscpy(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, 0 x0000, 0 x0000,
xfer_buffer, xfer_length, 1000 );
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);
strscpy(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);
strscpy(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, 0 x0000, 0 x0000,
xfer_buffer, xfer_length, 1000 );
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);
strscpy(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);
strscpy(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);
strscpy(vub300->vub_name, "corrupt dynamic registers" ,
sizeof (vub300->vub_name));
return ;
}
copy_error_message:
strscpy(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 += scnprintf(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 ) {
strscpy(vub300->vub_name, "vub_default.bin" ,
sizeof (vub300->vub_name));
retval = request_firmware(&fw, vub300->vub_name, &card->dev);
if (retval < 0 ) {
strscpy(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);
timer_delete(&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 & 0 x003F;
int modulo_512_length = linear_length & 0 x01FF;
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 {
timer_delete(&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 == 0 x00) {
/*
* 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 = 0 x00;
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 = 0 x00;
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 = 0 x00;
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 (!resp_len)
return ;
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 ) && (0 x000000FF & cmd->resp[0 ]))
cmd->resp[0 ] &= 0 xFFFFFF00;
}
/* 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) {
strscpy(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 = 0 xFF & (cmd->arg >> 24 );
u8 cmd1 = 0 xFF & (cmd->arg >> 16 );
u8 cmd2 = 0 xFF & (cmd->arg >> 8 );
u8 cmd3 = 0 xFF & (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 = 0 x00;
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 = 0 x00;
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 ((0 x80000000 & cmd->arg) == 0 x80000000) {
/*
* a write to a dynamic register
* nullifies our offloaded value
*/
vub300->sdio_register[i].prepared = 0 ;
return 0 ;
} else {
u8 checksum = 0 x00;
u8 rsp0 = 0 x00;
u8 rsp1 = 0 x00;
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,
0 x00, 0 x00, buf, buf_array_size, 1000 );
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,
0 x0000, 0 x0000, NULL, 0 , 1000 );
/* 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,
0 x0001, 0 x0000, NULL, 0 , 1000 );
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) {
set_current_state(TASK_RUNNING);
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);
set_current_state(TASK_INTERRUPTIBLE);
} else {
vub300->irq_enabled = 0 ;
}
kref_put(&vub300->kref, vub300_delete);
}
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,
};
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 = devm_mmc_alloc_host(&udev->dev, sizeof (*vub300));
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 ] = 0 x00;
vub300->cmnd.head.block_size[1 ] = 0 x00;
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 error4;
}
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0 ),
GET_HC_INF0,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0 x0000, 0 x0000, &vub300->hc_info,
sizeof (vub300->hc_info), 1000 );
if (retval < 0 )
goto error4;
retval =
usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0 ),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0 x0000, NULL, 0 , 1000 );
if (retval < 0 )
goto error4;
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,
0 x0000, 0 x0000, &vub300->system_port_status,
sizeof (vub300->system_port_status), 1000 );
if (retval < 0 ) {
goto error4;
} else if (sizeof (vub300->system_port_status) == retval) {
vub300->card_present =
(0 x0001 & vub300->system_port_status.port_flags) ? 1 : 0 ;
vub300->read_only =
(0 x0010 & vub300->system_port_status.port_flags) ? 1 : 0 ;
} else {
retval = -EINVAL;
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));
retval = mmc_add_host(mmc);
if (retval)
goto error6;
return 0 ;
error6:
timer_delete_sync(&vub300->inactivity_timer);
/*
* 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, 0 x0FFFF & 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" );
Messung V0.5 in Prozent C=96 H=90 G=93
¤ Dauer der Verarbeitung: 0.32 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland