root/drivers/staging/uwb/i1480/dfu/dfu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. i1480_rceb_check
  2. i1480_cmd
  3. i1480_print_state
  4. i1480_fw_upload

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Intel Wireless UWB Link 1480
   4  * Main driver
   5  *
   6  * Copyright (C) 2005-2006 Intel Corporation
   7  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   8  *
   9  * Common code for firmware upload used by the USB and PCI version;
  10  * i1480_fw_upload() takes a device descriptor and uses the function
  11  * pointers it provides to upload firmware and prepare the PHY.
  12  *
  13  * As well, provides common functions used by the rest of the code.
  14  */
  15 #include "i1480-dfu.h"
  16 #include <linux/errno.h>
  17 #include <linux/delay.h>
  18 #include <linux/pci.h>
  19 #include <linux/device.h>
  20 #include <linux/random.h>
  21 #include <linux/export.h>
  22 #include "../../uwb.h"
  23 
  24 /*
  25  * i1480_rceb_check - Check RCEB for expected field values
  26  * @i1480: pointer to device for which RCEB is being checked
  27  * @rceb: RCEB being checked
  28  * @cmd: which command the RCEB is related to
  29  * @context: expected context
  30  * @expected_type: expected event type
  31  * @expected_event: expected event
  32  *
  33  * If @cmd is NULL, do not print error messages, but still return an error
  34  * code.
  35  *
  36  * Return 0 if @rceb matches the expected values, -EINVAL otherwise.
  37  */
  38 int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
  39                      const char *cmd, u8 context, u8 expected_type,
  40                      unsigned expected_event)
  41 {
  42         int result = 0;
  43         struct device *dev = i1480->dev;
  44         if (rceb->bEventContext != context) {
  45                 if (cmd)
  46                         dev_err(dev, "%s: unexpected context id 0x%02x "
  47                                 "(expected 0x%02x)\n", cmd,
  48                                 rceb->bEventContext, context);
  49                 result = -EINVAL;
  50         }
  51         if (rceb->bEventType != expected_type) {
  52                 if (cmd)
  53                         dev_err(dev, "%s: unexpected event type 0x%02x "
  54                                 "(expected 0x%02x)\n", cmd,
  55                                 rceb->bEventType, expected_type);
  56                 result = -EINVAL;
  57         }
  58         if (le16_to_cpu(rceb->wEvent) != expected_event) {
  59                 if (cmd)
  60                         dev_err(dev, "%s: unexpected event 0x%04x "
  61                                 "(expected 0x%04x)\n", cmd,
  62                                 le16_to_cpu(rceb->wEvent), expected_event);
  63                 result = -EINVAL;
  64         }
  65         return result;
  66 }
  67 EXPORT_SYMBOL_GPL(i1480_rceb_check);
  68 
  69 
  70 /*
  71  * Execute a Radio Control Command
  72  *
  73  * Command data has to be in i1480->cmd_buf.
  74  *
  75  * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
  76  *          code on error.
  77  */
  78 ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
  79                   size_t reply_size)
  80 {
  81         ssize_t result;
  82         struct uwb_rceb *reply = i1480->evt_buf;
  83         struct uwb_rccb *cmd = i1480->cmd_buf;
  84         u16 expected_event = reply->wEvent;
  85         u8 expected_type = reply->bEventType;
  86         u8 context;
  87 
  88         init_completion(&i1480->evt_complete);
  89         i1480->evt_result = -EINPROGRESS;
  90         do {
  91                 get_random_bytes(&context, 1);
  92         } while (context == 0x00 || context == 0xff);
  93         cmd->bCommandContext = context;
  94         result = i1480->cmd(i1480, cmd_name, cmd_size);
  95         if (result < 0)
  96                 goto error;
  97         /* wait for the callback to report a event was received */
  98         result = wait_for_completion_interruptible_timeout(
  99                 &i1480->evt_complete, HZ);
 100         if (result == 0) {
 101                 result = -ETIMEDOUT;
 102                 goto error;
 103         }
 104         if (result < 0)
 105                 goto error;
 106         result = i1480->evt_result;
 107         if (result < 0) {
 108                 dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
 109                         cmd_name, result);
 110                 goto error;
 111         }
 112         /*
 113          * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
 114          * spurious notification after firmware is downloaded. So check whether
 115          * the receibed RCEB is such notification before assuming that the
 116          * command has failed.
 117          */
 118         if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
 119                              0, 0xfd, 0x0022) == 0) {
 120                 /* Now wait for the actual RCEB for this command. */
 121                 result = i1480->wait_init_done(i1480);
 122                 if (result < 0)
 123                         goto error;
 124                 result = i1480->evt_result;
 125         }
 126         if (result != reply_size) {
 127                 dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
 128                         cmd_name, result, reply_size);
 129                 result = -EINVAL;
 130                 goto error;
 131         }
 132         /* Verify we got the right event in response */
 133         result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
 134                                   expected_type, expected_event);
 135 error:
 136         return result;
 137 }
 138 EXPORT_SYMBOL_GPL(i1480_cmd);
 139 
 140 
 141 static
 142 int i1480_print_state(struct i1480 *i1480)
 143 {
 144         int result;
 145         u32 *buf = (u32 *) i1480->cmd_buf;
 146 
 147         result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
 148         if (result < 0) {
 149                 dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
 150                 goto error;
 151         }
 152         dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
 153 error:
 154         return result;
 155 }
 156 
 157 
 158 /*
 159  * PCI probe, firmware uploader
 160  *
 161  * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
 162  */
 163 int i1480_fw_upload(struct i1480 *i1480)
 164 {
 165         int result;
 166 
 167         result = i1480_pre_fw_upload(i1480);    /* PHY pre fw */
 168         if (result < 0 && result != -ENOENT) {
 169                 i1480_print_state(i1480);
 170                 goto error;
 171         }
 172         result = i1480_mac_fw_upload(i1480);    /* MAC fw */
 173         if (result < 0) {
 174                 if (result == -ENOENT)
 175                         dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
 176                                 i1480->mac_fw_name);
 177                 else
 178                         i1480_print_state(i1480);
 179                 goto error;
 180         }
 181         result = i1480_phy_fw_upload(i1480);    /* PHY fw */
 182         if (result < 0 && result != -ENOENT) {
 183                 i1480_print_state(i1480);
 184                 goto error_rc_release;
 185         }
 186         /*
 187          * FIXME: find some reliable way to check whether firmware is running
 188          * properly. Maybe use some standard request that has no side effects?
 189          */
 190         dev_info(i1480->dev, "firmware uploaded successfully\n");
 191 error_rc_release:
 192         if (i1480->rc_release)
 193                 i1480->rc_release(i1480);
 194         result = 0;
 195 error:
 196         return result;
 197 }
 198 EXPORT_SYMBOL_GPL(i1480_fw_upload);

/* [<][>][^][v][top][bottom][index][help] */