root/sound/firewire/fireworks/fireworks_transaction.c

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

DEFINITIONS

This source file includes following definitions.
  1. snd_efw_transaction_cmd
  2. snd_efw_transaction_run
  3. copy_resp_to_buf
  4. handle_resp_for_user
  5. handle_resp_for_kernel
  6. efw_response
  7. snd_efw_transaction_add_instance
  8. snd_efw_transaction_remove_instance
  9. snd_efw_transaction_bus_reset
  10. snd_efw_transaction_register
  11. snd_efw_transaction_unregister

   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 
  40 static DEFINE_SPINLOCK(instances_lock);
  41 static struct snd_efw *instances[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
  42 
  43 static DEFINE_SPINLOCK(transaction_queues_lock);
  44 static LIST_HEAD(transaction_queues);
  45 
  46 enum transaction_queue_state {
  47         STATE_PENDING,
  48         STATE_BUS_RESET,
  49         STATE_COMPLETE
  50 };
  51 
  52 struct 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 
  62 int 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 
  70 int 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 
 117 static void
 118 copy_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;
 160 end:
 161         spin_unlock_irq(&efw->lock);
 162 }
 163 
 164 static void
 165 handle_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);
 192 end:
 193         spin_unlock_irq(&instances_lock);
 194 }
 195 
 196 static void
 197 handle_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 
 225 static void
 226 efw_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         }
 254 end:
 255         fw_send_response(card, request, rcode);
 256 }
 257 
 258 void 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 
 274 void 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 
 289 void 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 
 304 static struct fw_address_handler resp_register_handler = {
 305         .length = SND_EFW_RESPONSE_MAXIMUM_BYTES,
 306         .address_callback = efw_response
 307 };
 308 
 309 int 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 
 320 void snd_efw_transaction_unregister(void)
 321 {
 322         WARN_ON(!list_empty(&transaction_queues));
 323         fw_core_remove_address_handler(&resp_register_handler);
 324 }

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