1795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez/* 2795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Intel Wireless WiMAX Connection 2400m 3795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Firmware uploader's USB specifics 4795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 5795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 6795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. 7795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 8795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Redistribution and use in source and binary forms, with or without 9795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * modification, are permitted provided that the following conditions 10795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * are met: 11795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 12795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * * Redistributions of source code must retain the above copyright 13795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * notice, this list of conditions and the following disclaimer. 14795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * * Redistributions in binary form must reproduce the above copyright 15795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * notice, this list of conditions and the following disclaimer in 16795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * the documentation and/or other materials provided with the 17795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * distribution. 18795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * * Neither the name of Intel Corporation nor the names of its 19795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * contributors may be used to endorse or promote products derived 20795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * from this software without specific prior written permission. 21795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 22795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 34795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 35795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Intel Corporation <linux-wimax@intel.com> 36795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Yanir Lubetkin <yanirx.lubetkin@intel.com> 37795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 38795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * - Initial implementation 39795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 40795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 41795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * - bus generic/specific split 42795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 43795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * THE PROCEDURE 44795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 45795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * See fw.c for the generic description of this procedure. 46795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 47795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * This file implements only the USB specifics. It boils down to how 48795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * to send a command and waiting for an acknowledgement from the 49795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * device. 50795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 51795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * This code (and process) is single threaded. It assumes it is the 52795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * only thread poking around (guaranteed by fw.c). 53795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 54795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * COMMAND EXECUTION 55795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 56795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * A write URB is posted with the buffer to the bulk output endpoint. 57795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 58795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * ACK RECEPTION 59795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 60795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * We just post a URB to the notification endpoint and wait for 61795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * data. We repeat until we get all the data we expect (as indicated 62795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * by the call from the bus generic code). 63795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 64795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * The data is not read from the bulk in endpoint for boot mode. 65795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 66795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * ROADMAP 67795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 68795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * i2400mu_bus_bm_cmd_send 69795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * i2400m_bm_cmd_prepare... 70795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * i2400mu_tx_bulk_out 71795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 72795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * i2400mu_bus_bm_wait_for_ack 73795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * i2400m_notif_submit 74795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez */ 75795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez#include <linux/usb.h> 765a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 77795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez#include "i2400m-usb.h" 78795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 79795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 80795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez#define D_SUBMODULE fw 81795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez#include "usb-debug-levels.h" 82795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 83795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 84795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez/* 85795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Synchronous write to the device 86795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 87795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Takes care of updating EDC counts and thus, handle device errors. 88795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez */ 89795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezstatic 90795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size) 91795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez{ 92795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez int result; 93795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct device *dev = &i2400mu->usb_iface->dev; 94795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez int len; 95795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct usb_endpoint_descriptor *epd; 96795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez int pipe, do_autopm = 1; 97795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 98795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = usb_autopm_get_interface(i2400mu->usb_iface); 99795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (result < 0) { 100795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "BM-CMD: can't get autopm: %d\n", result); 101795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez do_autopm = 0; 102795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 1032093586de29418820b89aae05746511392f8ad73Dirk Brandewie epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out); 104795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); 105795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezretry: 106296bd4bdd0a43c5e56ee310bcb9b4722e5d52db8Inaky Perez-Gonzalez result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, 200); 107795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez switch (result) { 108795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case 0: 109795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (len != buf_size) { 110795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "BM-CMD: short write (%u B vs %zu " 111795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez "expected)\n", len, buf_size); 112795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -EIO; 113795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez break; 114795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 115795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = len; 116795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez break; 117faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez case -EPIPE: 118faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez /* 119faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * Stall -- maybe the device is choking with our 120faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * requests. Clear it and give it some time. If they 121faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * happen to often, it might be another symptom, so we 122faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * reset. 123faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * 124faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * No error handling for usb_clear_halt(0; if it 125faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * works, the retry works; if it fails, this switch 126faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez * does the error handling for us. 127faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez */ 128faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez if (edc_inc(&i2400mu->urb_edc, 129faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { 130faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez dev_err(dev, "BM-CMD: too many stalls in " 131faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez "URB; resetting device\n"); 132faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez usb_queue_reset_device(i2400mu->usb_iface); 133faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez /* fallthrough */ 134faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez } else { 135faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez usb_clear_halt(i2400mu->usb_dev, pipe); 136faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez msleep(10); /* give the device some time */ 137faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez goto retry; 138faf57162e462eafe87458e21bf641f9d138f8171Inaky Perez-Gonzalez } 139795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -EINVAL: /* while removing driver */ 140795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ENODEV: /* dev disconnect ... */ 141795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ENOENT: /* just ignore it */ 142795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ESHUTDOWN: /* and exit */ 143795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ECONNRESET: 144795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -ESHUTDOWN; 145795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez break; 146795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ETIMEDOUT: /* bah... */ 147795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez break; 148795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez default: /* any other? */ 149795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (edc_inc(&i2400mu->urb_edc, 150795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { 151795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "BM-CMD: maximum errors in " 152795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez "URB exceeded; resetting device\n"); 153795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_queue_reset_device(i2400mu->usb_iface); 154795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -ENODEV; 155795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez break; 156795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 157795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "BM-CMD: URB error %d, retrying\n", 158795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result); 159795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto retry; 160795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 161795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (do_autopm) 162795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_autopm_put_interface(i2400mu->usb_iface); 163795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez return result; 164795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez} 165795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 166795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 167795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez/* 168795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Send a boot-mode command over the bulk-out pipe 169795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 170795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Command can be a raw command, which requires no preparation (and 171795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * which might not even be following the command format). Checks that 17225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * the right amount of data was transferred. 173795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 174795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * To satisfy USB requirements (no onstack, vmalloc or in data segment 175795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * buffers), we copy the command to i2400m->bm_cmd_buf and send it from 176795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * there. 177795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 178795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @flags: pass thru from i2400m_bm_cmd() 179795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @return: cmd_size if ok, < 0 errno code on error. 180795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez */ 181795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m, 182795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez const struct i2400m_bootrom_header *_cmd, 183795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez size_t cmd_size, int flags) 184795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez{ 185795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez ssize_t result; 186795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct device *dev = i2400m_dev(i2400m); 187795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); 188795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd); 189795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct i2400m_bootrom_header *cmd; 190795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez size_t cmd_size_a = ALIGN(cmd_size, 16); /* USB restriction */ 191795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 192795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez d_fnstart(8, dev, "(i2400m %p cmd %p size %zu)\n", 193795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez i2400m, _cmd, cmd_size); 194795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -E2BIG; 195795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (cmd_size > I2400M_BM_CMD_BUF_SIZE) 196795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_too_big; 19777e1251a7cc64c1e483a31c41c139fdf8121e75eInaky Perez-Gonzalez if (_cmd != i2400m->bm_cmd_buf) 19877e1251a7cc64c1e483a31c41c139fdf8121e75eInaky Perez-Gonzalez memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); 199795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez cmd = i2400m->bm_cmd_buf; 200795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (cmd_size_a > cmd_size) /* Zero pad space */ 201795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); 202795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if ((flags & I2400M_BM_CMD_RAW) == 0) { 203795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0)) 204795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_warn(dev, "SW BUG: response_required == 0\n"); 205795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez i2400m_bm_cmd_prepare(cmd); 206795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 207795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = i2400mu_tx_bulk_out(i2400mu, i2400m->bm_cmd_buf, cmd_size); 208795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (result < 0) { 209795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "boot-mode cmd %d: cannot send: %zd\n", 210795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez opcode, result); 211795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_cmd_send; 212795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 213795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (result != cmd_size) { /* all was transferred? */ 214795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "boot-mode cmd %d: incomplete transfer " 215795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez "(%zu vs %zu submitted)\n", opcode, result, cmd_size); 216795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -EIO; 217795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_cmd_size; 218795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 219795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_cmd_size: 220795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_cmd_send: 221795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_too_big: 222795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez d_fnend(8, dev, "(i2400m %p cmd %p size %zu) = %zd\n", 223795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez i2400m, _cmd, cmd_size, result); 224795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez return result; 225795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez} 226795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 227795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 228795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezstatic 229795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezvoid __i2400mu_bm_notif_cb(struct urb *urb) 230795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez{ 231795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez complete(urb->context); 232795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez} 233795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 234795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 235795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez/* 236795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * submit a read to the notification endpoint 237795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 238795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @i2400m: device descriptor 239795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @urb: urb to use 240795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @completion: completion varible to complete when done 241795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 242795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Data is always read to i2400m->bm_ack_buf 243795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez */ 244795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezstatic 245795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezint i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb, 246795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct completion *completion) 247795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez{ 248795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct i2400m *i2400m = &i2400mu->i2400m; 249795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct usb_endpoint_descriptor *epd; 250795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez int pipe; 251795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 2522093586de29418820b89aae05746511392f8ad73Dirk Brandewie epd = usb_get_epd(i2400mu->usb_iface, 2532093586de29418820b89aae05746511392f8ad73Dirk Brandewie i2400mu->endpoint_cfg.notification); 254795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress); 255795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_fill_int_urb(urb, i2400mu->usb_dev, pipe, 256795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE, 257795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez __i2400mu_bm_notif_cb, completion, 258795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez epd->bInterval); 259795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez return usb_submit_urb(urb, GFP_KERNEL); 260795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez} 261795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 262795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 263795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez/* 264795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Read an ack from the notification endpoint 265795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 266795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @i2400m: 267795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @_ack: pointer to where to store the read data 268795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * @ack_size: how many bytes we should read 269795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 270795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Returns: < 0 errno code on error; otherwise, amount of received bytes. 271795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * 272795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * Submits a notification read, appends the read data to the given ack 273795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * buffer and then repeats (until @ack_size bytes have been 274795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez * received). 275795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez */ 276795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m, 277795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct i2400m_bootrom_header *_ack, 278795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez size_t ack_size) 279795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez{ 280795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez ssize_t result = -ENOMEM; 281795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct device *dev = i2400m_dev(i2400m); 282795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); 283795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez struct urb notif_urb; 284795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez void *ack = _ack; 285795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez size_t offset, len; 286795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez long val; 287795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez int do_autopm = 1; 288795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez DECLARE_COMPLETION_ONSTACK(notif_completion); 289795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 290795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez d_fnstart(8, dev, "(i2400m %p ack %p size %zu)\n", 291795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez i2400m, ack, ack_size); 292795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez BUG_ON(_ack == i2400m->bm_ack_buf); 293795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = usb_autopm_get_interface(i2400mu->usb_iface); 294795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (result < 0) { 295795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "BM-ACK: can't get autopm: %d\n", (int) result); 296795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez do_autopm = 0; 297795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 298795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_init_urb(¬if_urb); /* ready notifications */ 299795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_get_urb(¬if_urb); 300795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez offset = 0; 301795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez while (offset < ack_size) { 302795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez init_completion(¬if_completion); 303795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = i2400mu_notif_submit(i2400mu, ¬if_urb, 304795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez ¬if_completion); 305795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (result < 0) 306795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_notif_urb_submit; 307795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez val = wait_for_completion_interruptible_timeout( 308795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez ¬if_completion, HZ); 309795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (val == 0) { 310795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -ETIMEDOUT; 311795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_kill_urb(¬if_urb); /* Timedout */ 312795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_notif_wait; 313795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 314795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (val == -ERESTARTSYS) { 315795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -EINTR; /* Interrupted */ 316795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_kill_urb(¬if_urb); 317795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_notif_wait; 318795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 319795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = notif_urb.status; /* How was the ack? */ 320795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez switch (result) { 321795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case 0: 322795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez break; 323795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -EINVAL: /* while removing driver */ 324795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ENODEV: /* dev disconnect ... */ 325795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ENOENT: /* just ignore it */ 326795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ESHUTDOWN: /* and exit */ 327795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez case -ECONNRESET: 328795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = -ESHUTDOWN; 329795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_dev_gone; 330795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez default: /* any other? */ 331795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_kill_urb(¬if_urb); /* Timedout */ 332795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (edc_inc(&i2400mu->urb_edc, 333795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) 334795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto error_exceeded; 335795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "BM-ACK: URB error %d, " 336795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez "retrying\n", notif_urb.status); 337795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez continue; /* retry */ 338795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 339795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (notif_urb.actual_length == 0) { 340795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez d_printf(6, dev, "ZLP received, retrying\n"); 341795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez continue; 342795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 343795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez /* Got data, append it to the buffer */ 344795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez len = min(ack_size - offset, (size_t) notif_urb.actual_length); 345795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez memcpy(ack + offset, i2400m->bm_ack_buf, len); 346795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez offset += len; 347795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez } 348795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez result = offset; 349795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_notif_urb_submit: 350795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_notif_wait: 351795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_dev_gone: 352795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezout: 353795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez if (do_autopm) 354795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_autopm_put_interface(i2400mu->usb_iface); 35559bdc4be0b819173a8f840fc11ccb82d6f2ca64bInaky Perez-Gonzalez d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n", 35659bdc4be0b819173a8f840fc11ccb82d6f2ca64bInaky Perez-Gonzalez i2400m, ack, ack_size, (long) result); 357795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez return result; 358795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez 359795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalezerror_exceeded: 360795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez dev_err(dev, "bm: maximum errors in notification URB exceeded; " 361795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez "resetting device\n"); 362795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez usb_queue_reset_device(i2400mu->usb_iface); 363795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez goto out; 364795038107b0078ee5ad3ad33327fe1c3520f6bf2Inaky Perez-Gonzalez} 365