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