linux/sound/firewire/fireworks/fireworks_transaction.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * fireworks_transaction.c - a part of driver for Fireworks based devices
   4 *
   5 * Copyright (c) 2013-2014 Takashi Sakamoto
   6 */
   7
   8/*
   9 * Fireworks have its own transaction. The transaction can be delivered by AV/C
  10 * Vendor Specific command frame or usual asynchronous transaction. At least,
  11 * Windows driver and firmware version 5.5 or later don't use AV/C command.
  12 *
  13 * Transaction substance:
  14 *  At first, 6 data exist. Following to the data, parameters for each command
  15 *  exist. All of the parameters are 32 bit aligned to big endian.
  16 *   data[0]:   Length of transaction substance
  17 *   data[1]:   Transaction version
  18 *   data[2]:   Sequence number. This is incremented by the device
  19 *   data[3]:   Transaction category
  20 *   data[4]:   Transaction command
  21 *   data[5]:   Return value in response.
  22 *   data[6-]:  Parameters
  23 *
  24 * Transaction address:
  25 *  command:    0xecc000000000
  26 *  response:   0xecc080000000 (default)
  27 *
  28 * I note that the address for response can be changed by command. But this
  29 * module uses the default address.
  30 */
  31#include "./fireworks.h"
  32
  33#define MEMORY_SPACE_EFW_COMMAND        0xecc000000000ULL
  34#define MEMORY_SPACE_EFW_RESPONSE       0xecc080000000ULL
  35
  36#define ERROR_RETRIES 3
  37#define ERROR_DELAY_MS 5
  38#define EFC_TIMEOUT_MS 125
  39
  40static DEFINE_SPINLOCK(instances_lock);
  41static struct snd_efw *instances[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
  42
  43static DEFINE_SPINLOCK(transaction_queues_lock);
  44static LIST_HEAD(transaction_queues);
  45
  46enum transaction_queue_state {
  47        STATE_PENDING,
  48        STATE_BUS_RESET,
  49        STATE_COMPLETE
  50};
  51
  52struct transaction_queue {
  53        struct list_head list;
  54        struct fw_unit *unit;
  55        void *buf;
  56        unsigned int size;
  57        u32 seqnum;
  58        enum transaction_queue_state state;
  59        wait_queue_head_t wait;
  60};
  61
  62int snd_efw_transaction_cmd(struct fw_unit *unit,
  63                            const void *cmd, unsigned int size)
  64{
  65        return snd_fw_transaction(unit, TCODE_WRITE_BLOCK_REQUEST,
  66                                  MEMORY_SPACE_EFW_COMMAND,
  67                                  (void *)cmd, size, 0);
  68}
  69
  70int snd_efw_transaction_run(struct fw_unit *unit,
  71                            const void *cmd, unsigned int cmd_size,
  72                            void *resp, unsigned int resp_size)
  73{
  74        struct transaction_queue t;
  75        unsigned int tries;
  76        int ret;
  77
  78        t.unit = unit;
  79        t.buf = resp;
  80        t.size = resp_size;
  81        t.seqnum = be32_to_cpu(((struct snd_efw_transaction *)cmd)->seqnum) + 1;
  82        t.state = STATE_PENDING;
  83        init_waitqueue_head(&t.wait);
  84
  85        spin_lock_irq(&transaction_queues_lock);
  86        list_add_tail(&t.list, &transaction_queues);
  87        spin_unlock_irq(&transaction_queues_lock);
  88
  89        tries = 0;
  90        do {
  91                ret = snd_efw_transaction_cmd(t.unit, (void *)cmd, cmd_size);
  92                if (ret < 0)
  93                        break;
  94
  95                wait_event_timeout(t.wait, t.state != STATE_PENDING,
  96                                   msecs_to_jiffies(EFC_TIMEOUT_MS));
  97
  98                if (t.state == STATE_COMPLETE) {
  99                        ret = t.size;
 100                        break;
 101                } else if (t.state == STATE_BUS_RESET) {
 102                        msleep(ERROR_DELAY_MS);
 103                } else if (++tries >= ERROR_RETRIES) {
 104                        dev_err(&t.unit->device, "EFW transaction timed out\n");
 105                        ret = -EIO;
 106                        break;
 107                }
 108        } while (1);
 109
 110        spin_lock_irq(&transaction_queues_lock);
 111        list_del(&t.list);
 112        spin_unlock_irq(&transaction_queues_lock);
 113
 114        return ret;
 115}
 116
 117static void
 118copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
 119{
 120        size_t capacity, till_end;
 121        struct snd_efw_transaction *t;
 122
 123        t = (struct snd_efw_transaction *)data;
 124        length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
 125
 126        spin_lock_irq(&efw->lock);
 127
 128        if (efw->push_ptr < efw->pull_ptr)
 129                capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
 130        else
 131                capacity = snd_efw_resp_buf_size -
 132                           (unsigned int)(efw->push_ptr - efw->pull_ptr);
 133
 134        /* confirm enough space for this response */
 135        if (capacity < length) {
 136                *rcode = RCODE_CONFLICT_ERROR;
 137                goto end;
 138        }
 139
 140        /* copy to ring buffer */
 141        while (length > 0) {
 142                till_end = snd_efw_resp_buf_size -
 143                           (unsigned int)(efw->push_ptr - efw->resp_buf);
 144                till_end = min_t(unsigned int, length, till_end);
 145
 146                memcpy(efw->push_ptr, data, till_end);
 147
 148                efw->push_ptr += till_end;
 149                if (efw->push_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
 150                        efw->push_ptr -= snd_efw_resp_buf_size;
 151
 152                length -= till_end;
 153                data += till_end;
 154        }
 155
 156        /* for hwdep */
 157        wake_up(&efw->hwdep_wait);
 158
 159        *rcode = RCODE_COMPLETE;
 160end:
 161        spin_unlock_irq(&efw->lock);
 162}
 163
 164static void
 165handle_resp_for_user(struct fw_card *card, int generation, int source,
 166                     void *data, size_t length, int *rcode)
 167{
 168        struct fw_device *device;
 169        struct snd_efw *efw;
 170        unsigned int i;
 171
 172        spin_lock_irq(&instances_lock);
 173
 174        for (i = 0; i < SNDRV_CARDS; i++) {
 175                efw = instances[i];
 176                if (efw == NULL)
 177                        continue;
 178                device = fw_parent_device(efw->unit);
 179                if ((device->card != card) ||
 180                    (device->generation != generation))
 181                        continue;
 182                smp_rmb();      /* node id vs. generation */
 183                if (device->node_id != source)
 184                        continue;
 185
 186                break;
 187        }
 188        if (i == SNDRV_CARDS)
 189                goto end;
 190
 191        copy_resp_to_buf(efw, data, length, rcode);
 192end:
 193        spin_unlock_irq(&instances_lock);
 194}
 195
 196static void
 197handle_resp_for_kernel(struct fw_card *card, int generation, int source,
 198                       void *data, size_t length, int *rcode, u32 seqnum)
 199{
 200        struct fw_device *device;
 201        struct transaction_queue *t;
 202        unsigned long flags;
 203
 204        spin_lock_irqsave(&transaction_queues_lock, flags);
 205        list_for_each_entry(t, &transaction_queues, list) {
 206                device = fw_parent_device(t->unit);
 207                if ((device->card != card) ||
 208                    (device->generation != generation))
 209                        continue;
 210                smp_rmb();      /* node_id vs. generation */
 211                if (device->node_id != source)
 212                        continue;
 213
 214                if ((t->state == STATE_PENDING) && (t->seqnum == seqnum)) {
 215                        t->state = STATE_COMPLETE;
 216                        t->size = min_t(unsigned int, length, t->size);
 217                        memcpy(t->buf, data, t->size);
 218                        wake_up(&t->wait);
 219                        *rcode = RCODE_COMPLETE;
 220                }
 221        }
 222        spin_unlock_irqrestore(&transaction_queues_lock, flags);
 223}
 224
 225static void
 226efw_response(struct fw_card *card, struct fw_request *request,
 227             int tcode, int destination, int source,
 228             int generation, unsigned long long offset,
 229             void *data, size_t length, void *callback_data)
 230{
 231        int rcode, dummy;
 232        u32 seqnum;
 233
 234        rcode = RCODE_TYPE_ERROR;
 235        if (length < sizeof(struct snd_efw_transaction)) {
 236                rcode = RCODE_DATA_ERROR;
 237                goto end;
 238        } else if (offset != MEMORY_SPACE_EFW_RESPONSE) {
 239                rcode = RCODE_ADDRESS_ERROR;
 240                goto end;
 241        }
 242
 243        seqnum = be32_to_cpu(((struct snd_efw_transaction *)data)->seqnum);
 244        if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 1) {
 245                handle_resp_for_kernel(card, generation, source,
 246                                       data, length, &rcode, seqnum);
 247                if (snd_efw_resp_buf_debug)
 248                        handle_resp_for_user(card, generation, source,
 249                                             data, length, &dummy);
 250        } else {
 251                handle_resp_for_user(card, generation, source,
 252                                     data, length, &rcode);
 253        }
 254end:
 255        fw_send_response(card, request, rcode);
 256}
 257
 258void snd_efw_transaction_add_instance(struct snd_efw *efw)
 259{
 260        unsigned int i;
 261
 262        spin_lock_irq(&instances_lock);
 263
 264        for (i = 0; i < SNDRV_CARDS; i++) {
 265                if (instances[i] != NULL)
 266                        continue;
 267                instances[i] = efw;
 268                break;
 269        }
 270
 271        spin_unlock_irq(&instances_lock);
 272}
 273
 274void snd_efw_transaction_remove_instance(struct snd_efw *efw)
 275{
 276        unsigned int i;
 277
 278        spin_lock_irq(&instances_lock);
 279
 280        for (i = 0; i < SNDRV_CARDS; i++) {
 281                if (instances[i] != efw)
 282                        continue;
 283                instances[i] = NULL;
 284        }
 285
 286        spin_unlock_irq(&instances_lock);
 287}
 288
 289void snd_efw_transaction_bus_reset(struct fw_unit *unit)
 290{
 291        struct transaction_queue *t;
 292
 293        spin_lock_irq(&transaction_queues_lock);
 294        list_for_each_entry(t, &transaction_queues, list) {
 295                if ((t->unit == unit) &&
 296                    (t->state == STATE_PENDING)) {
 297                        t->state = STATE_BUS_RESET;
 298                        wake_up(&t->wait);
 299                }
 300        }
 301        spin_unlock_irq(&transaction_queues_lock);
 302}
 303
 304static struct fw_address_handler resp_register_handler = {
 305        .length = SND_EFW_RESPONSE_MAXIMUM_BYTES,
 306        .address_callback = efw_response
 307};
 308
 309int snd_efw_transaction_register(void)
 310{
 311        static const struct fw_address_region resp_register_region = {
 312                .start  = MEMORY_SPACE_EFW_RESPONSE,
 313                .end    = MEMORY_SPACE_EFW_RESPONSE +
 314                          SND_EFW_RESPONSE_MAXIMUM_BYTES
 315        };
 316        return fw_core_add_address_handler(&resp_register_handler,
 317                                           &resp_register_region);
 318}
 319
 320void snd_efw_transaction_unregister(void)
 321{
 322        WARN_ON(!list_empty(&transaction_queues));
 323        fw_core_remove_address_handler(&resp_register_handler);
 324}
 325