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        t = (struct snd_efw_transaction *)data;
 125        length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
 126
 127        spin_lock_irq(&efw->lock);
 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        wake_up(&efw->hwdep_wait);
 159
 160        *rcode = RCODE_COMPLETE;
 161end:
 162        spin_unlock_irq(&efw->lock);
 163}
 164
 165static void
 166handle_resp_for_user(struct fw_card *card, int generation, int source,
 167                     void *data, size_t length, int *rcode)
 168{
 169        struct fw_device *device;
 170        struct snd_efw *efw;
 171        unsigned int i;
 172
 173        spin_lock_irq(&instances_lock);
 174
 175        for (i = 0; i < SNDRV_CARDS; i++) {
 176                efw = instances[i];
 177                if (efw == NULL)
 178                        continue;
 179                device = fw_parent_device(efw->unit);
 180                if ((device->card != card) ||
 181                    (device->generation != generation))
 182                        continue;
 183                smp_rmb();      /* node id vs. generation */
 184                if (device->node_id != source)
 185                        continue;
 186
 187                break;
 188        }
 189        if (i == SNDRV_CARDS)
 190                goto end;
 191
 192        copy_resp_to_buf(efw, data, length, rcode);
 193end:
 194        spin_unlock_irq(&instances_lock);
 195}
 196
 197static void
 198handle_resp_for_kernel(struct fw_card *card, int generation, int source,
 199                       void *data, size_t length, int *rcode, u32 seqnum)
 200{
 201        struct fw_device *device;
 202        struct transaction_queue *t;
 203        unsigned long flags;
 204
 205        spin_lock_irqsave(&transaction_queues_lock, flags);
 206        list_for_each_entry(t, &transaction_queues, list) {
 207                device = fw_parent_device(t->unit);
 208                if ((device->card != card) ||
 209                    (device->generation != generation))
 210                        continue;
 211                smp_rmb();      /* node_id vs. generation */
 212                if (device->node_id != source)
 213                        continue;
 214
 215                if ((t->state == STATE_PENDING) && (t->seqnum == seqnum)) {
 216                        t->state = STATE_COMPLETE;
 217                        t->size = min_t(unsigned int, length, t->size);
 218                        memcpy(t->buf, data, t->size);
 219                        wake_up(&t->wait);
 220                        *rcode = RCODE_COMPLETE;
 221                }
 222        }
 223        spin_unlock_irqrestore(&transaction_queues_lock, flags);
 224}
 225
 226static void
 227efw_response(struct fw_card *card, struct fw_request *request,
 228             int tcode, int destination, int source,
 229             int generation, unsigned long long offset,
 230             void *data, size_t length, void *callback_data)
 231{
 232        int rcode, dummy;
 233        u32 seqnum;
 234
 235        rcode = RCODE_TYPE_ERROR;
 236        if (length < sizeof(struct snd_efw_transaction)) {
 237                rcode = RCODE_DATA_ERROR;
 238                goto end;
 239        } else if (offset != MEMORY_SPACE_EFW_RESPONSE) {
 240                rcode = RCODE_ADDRESS_ERROR;
 241                goto end;
 242        }
 243
 244        seqnum = be32_to_cpu(((struct snd_efw_transaction *)data)->seqnum);
 245        if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 1) {
 246                handle_resp_for_kernel(card, generation, source,
 247                                       data, length, &rcode, seqnum);
 248                if (snd_efw_resp_buf_debug)
 249                        handle_resp_for_user(card, generation, source,
 250                                             data, length, &dummy);
 251        } else {
 252                handle_resp_for_user(card, generation, source,
 253                                     data, length, &rcode);
 254        }
 255end:
 256        fw_send_response(card, request, rcode);
 257}
 258
 259void snd_efw_transaction_add_instance(struct snd_efw *efw)
 260{
 261        unsigned int i;
 262
 263        spin_lock_irq(&instances_lock);
 264
 265        for (i = 0; i < SNDRV_CARDS; i++) {
 266                if (instances[i] != NULL)
 267                        continue;
 268                instances[i] = efw;
 269                break;
 270        }
 271
 272        spin_unlock_irq(&instances_lock);
 273}
 274
 275void snd_efw_transaction_remove_instance(struct snd_efw *efw)
 276{
 277        unsigned int i;
 278
 279        spin_lock_irq(&instances_lock);
 280
 281        for (i = 0; i < SNDRV_CARDS; i++) {
 282                if (instances[i] != efw)
 283                        continue;
 284                instances[i] = NULL;
 285        }
 286
 287        spin_unlock_irq(&instances_lock);
 288}
 289
 290void snd_efw_transaction_bus_reset(struct fw_unit *unit)
 291{
 292        struct transaction_queue *t;
 293
 294        spin_lock_irq(&transaction_queues_lock);
 295        list_for_each_entry(t, &transaction_queues, list) {
 296                if ((t->unit == unit) &&
 297                    (t->state == STATE_PENDING)) {
 298                        t->state = STATE_BUS_RESET;
 299                        wake_up(&t->wait);
 300                }
 301        }
 302        spin_unlock_irq(&transaction_queues_lock);
 303}
 304
 305static struct fw_address_handler resp_register_handler = {
 306        .length = SND_EFW_RESPONSE_MAXIMUM_BYTES,
 307        .address_callback = efw_response
 308};
 309
 310int snd_efw_transaction_register(void)
 311{
 312        static const struct fw_address_region resp_register_region = {
 313                .start  = MEMORY_SPACE_EFW_RESPONSE,
 314                .end    = MEMORY_SPACE_EFW_RESPONSE +
 315                          SND_EFW_RESPONSE_MAXIMUM_BYTES
 316        };
 317        return fw_core_add_address_handler(&resp_register_handler,
 318                                           &resp_register_region);
 319}
 320
 321void snd_efw_transaction_unregister(void)
 322{
 323        WARN_ON(!list_empty(&transaction_queues));
 324        fw_core_remove_address_handler(&resp_register_handler);
 325}
 326