linux/sound/firewire/fcp.c
<<
>>
Prefs
   1/*
   2 * Function Control Protocol (IEC 61883-1) helper functions
   3 *
   4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   5 * Licensed under the terms of the GNU General Public License, version 2.
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/firewire.h>
  10#include <linux/firewire-constants.h>
  11#include <linux/list.h>
  12#include <linux/module.h>
  13#include <linux/slab.h>
  14#include <linux/sched.h>
  15#include <linux/spinlock.h>
  16#include <linux/wait.h>
  17#include <linux/delay.h>
  18#include "fcp.h"
  19#include "lib.h"
  20#include "amdtp.h"
  21
  22#define CTS_AVC 0x00
  23
  24#define ERROR_RETRIES   3
  25#define ERROR_DELAY_MS  5
  26#define FCP_TIMEOUT_MS  125
  27
  28int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate,
  29                            enum avc_general_plug_dir dir,
  30                            unsigned short pid)
  31{
  32        unsigned int sfc;
  33        u8 *buf;
  34        bool flag;
  35        int err;
  36
  37        flag = false;
  38        for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {
  39                if (amdtp_rate_table[sfc] == rate) {
  40                        flag = true;
  41                        break;
  42                }
  43        }
  44        if (!flag)
  45                return -EINVAL;
  46
  47        buf = kzalloc(8, GFP_KERNEL);
  48        if (buf == NULL)
  49                return -ENOMEM;
  50
  51        buf[0] = 0x00;          /* AV/C CONTROL */
  52        buf[1] = 0xff;          /* UNIT */
  53        if (dir == AVC_GENERAL_PLUG_DIR_IN)
  54                buf[2] = 0x19;  /* INPUT PLUG SIGNAL FORMAT */
  55        else
  56                buf[2] = 0x18;  /* OUTPUT PLUG SIGNAL FORMAT */
  57        buf[3] = 0xff & pid;    /* plug id */
  58        buf[4] = 0x90;          /* EOH_1, Form_1, FMT. AM824 */
  59        buf[5] = 0x07 & sfc;    /* FDF-hi. AM824, frequency */
  60        buf[6] = 0xff;          /* FDF-mid. AM824, SYT hi (not used)*/
  61        buf[7] = 0xff;          /* FDF-low. AM824, SYT lo (not used) */
  62
  63        /* do transaction and check buf[1-5] are the same against command */
  64        err = fcp_avc_transaction(unit, buf, 8, buf, 8,
  65                                  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
  66        if (err >= 0 && err < 8)
  67                err = -EIO;
  68        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
  69                err = -ENOSYS;
  70        else if (buf[0] == 0x0a) /* REJECTED */
  71                err = -EINVAL;
  72        if (err < 0)
  73                goto end;
  74
  75        err = 0;
  76end:
  77        kfree(buf);
  78        return err;
  79}
  80EXPORT_SYMBOL(avc_general_set_sig_fmt);
  81
  82int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate,
  83                            enum avc_general_plug_dir dir,
  84                            unsigned short pid)
  85{
  86        unsigned int sfc;
  87        u8 *buf;
  88        int err;
  89
  90        buf = kzalloc(8, GFP_KERNEL);
  91        if (buf == NULL)
  92                return -ENOMEM;
  93
  94        buf[0] = 0x01;          /* AV/C STATUS */
  95        buf[1] = 0xff;          /* Unit */
  96        if (dir == AVC_GENERAL_PLUG_DIR_IN)
  97                buf[2] = 0x19;  /* INPUT PLUG SIGNAL FORMAT */
  98        else
  99                buf[2] = 0x18;  /* OUTPUT PLUG SIGNAL FORMAT */
 100        buf[3] = 0xff & pid;    /* plug id */
 101        buf[4] = 0x90;          /* EOH_1, Form_1, FMT. AM824 */
 102        buf[5] = 0xff;          /* FDF-hi. AM824, frequency */
 103        buf[6] = 0xff;          /* FDF-mid. AM824, SYT hi (not used) */
 104        buf[7] = 0xff;          /* FDF-low. AM824, SYT lo (not used) */
 105
 106        /* do transaction and check buf[1-4] are the same against command */
 107        err = fcp_avc_transaction(unit, buf, 8, buf, 8,
 108                                  BIT(1) | BIT(2) | BIT(3) | BIT(4));
 109        if (err >= 0 && err < 8)
 110                err = -EIO;
 111        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
 112                err = -ENOSYS;
 113        else if (buf[0] == 0x0a) /* REJECTED */
 114                err = -EINVAL;
 115        else if (buf[0] == 0x0b) /* IN TRANSITION */
 116                err = -EAGAIN;
 117        if (err < 0)
 118                goto end;
 119
 120        /* check sfc field and pick up rate */
 121        sfc = 0x07 & buf[5];
 122        if (sfc >= CIP_SFC_COUNT) {
 123                err = -EAGAIN;  /* also in transition */
 124                goto end;
 125        }
 126
 127        *rate = amdtp_rate_table[sfc];
 128        err = 0;
 129end:
 130        kfree(buf);
 131        return err;
 132}
 133EXPORT_SYMBOL(avc_general_get_sig_fmt);
 134
 135int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type,
 136                              unsigned int subunit_id, unsigned int subfunction,
 137                              u8 info[AVC_PLUG_INFO_BUF_BYTES])
 138{
 139        u8 *buf;
 140        int err;
 141
 142        /* extended subunit in spec.4.2 is not supported */
 143        if ((subunit_type == 0x1E) || (subunit_id == 5))
 144                return -EINVAL;
 145
 146        buf = kzalloc(8, GFP_KERNEL);
 147        if (buf == NULL)
 148                return -ENOMEM;
 149
 150        buf[0] = 0x01;  /* AV/C STATUS */
 151        /* UNIT or Subunit, Functionblock */
 152        buf[1] = ((subunit_type & 0x1f) << 3) | (subunit_id & 0x7);
 153        buf[2] = 0x02;  /* PLUG INFO */
 154        buf[3] = 0xff & subfunction;
 155
 156        err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2));
 157        if (err >= 0 && err < 8)
 158                err = -EIO;
 159        else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
 160                err = -ENOSYS;
 161        else if (buf[0] == 0x0a) /* REJECTED */
 162                err = -EINVAL;
 163        else if (buf[0] == 0x0b) /* IN TRANSITION */
 164                err = -EAGAIN;
 165        if (err < 0)
 166                goto end;
 167
 168        info[0] = buf[4];
 169        info[1] = buf[5];
 170        info[2] = buf[6];
 171        info[3] = buf[7];
 172
 173        err = 0;
 174end:
 175        kfree(buf);
 176        return err;
 177}
 178EXPORT_SYMBOL(avc_general_get_plug_info);
 179
 180static DEFINE_SPINLOCK(transactions_lock);
 181static LIST_HEAD(transactions);
 182
 183enum fcp_state {
 184        STATE_PENDING,
 185        STATE_BUS_RESET,
 186        STATE_COMPLETE,
 187        STATE_DEFERRED,
 188};
 189
 190struct fcp_transaction {
 191        struct list_head list;
 192        struct fw_unit *unit;
 193        void *response_buffer;
 194        unsigned int response_size;
 195        unsigned int response_match_bytes;
 196        enum fcp_state state;
 197        wait_queue_head_t wait;
 198        bool deferrable;
 199};
 200
 201/**
 202 * fcp_avc_transaction - send an AV/C command and wait for its response
 203 * @unit: a unit on the target device
 204 * @command: a buffer containing the command frame; must be DMA-able
 205 * @command_size: the size of @command
 206 * @response: a buffer for the response frame
 207 * @response_size: the maximum size of @response
 208 * @response_match_bytes: a bitmap specifying the bytes used to detect the
 209 *                        correct response frame
 210 *
 211 * This function sends a FCP command frame to the target and waits for the
 212 * corresponding response frame to be returned.
 213 *
 214 * Because it is possible for multiple FCP transactions to be active at the
 215 * same time, the correct response frame is detected by the value of certain
 216 * bytes.  These bytes must be set in @response before calling this function,
 217 * and the corresponding bits must be set in @response_match_bytes.
 218 *
 219 * @command and @response can point to the same buffer.
 220 *
 221 * Returns the actual size of the response frame, or a negative error code.
 222 */
 223int fcp_avc_transaction(struct fw_unit *unit,
 224                        const void *command, unsigned int command_size,
 225                        void *response, unsigned int response_size,
 226                        unsigned int response_match_bytes)
 227{
 228        struct fcp_transaction t;
 229        int tcode, ret, tries = 0;
 230
 231        t.unit = unit;
 232        t.response_buffer = response;
 233        t.response_size = response_size;
 234        t.response_match_bytes = response_match_bytes;
 235        t.state = STATE_PENDING;
 236        init_waitqueue_head(&t.wait);
 237
 238        if (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03)
 239                t.deferrable = true;
 240
 241        spin_lock_irq(&transactions_lock);
 242        list_add_tail(&t.list, &transactions);
 243        spin_unlock_irq(&transactions_lock);
 244
 245        for (;;) {
 246                tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST
 247                                          : TCODE_WRITE_BLOCK_REQUEST;
 248                ret = snd_fw_transaction(t.unit, tcode,
 249                                         CSR_REGISTER_BASE + CSR_FCP_COMMAND,
 250                                         (void *)command, command_size, 0);
 251                if (ret < 0)
 252                        break;
 253deferred:
 254                wait_event_timeout(t.wait, t.state != STATE_PENDING,
 255                                   msecs_to_jiffies(FCP_TIMEOUT_MS));
 256
 257                if (t.state == STATE_DEFERRED) {
 258                        /*
 259                         * 'AV/C General Specification' define no time limit
 260                         * on command completion once an INTERIM response has
 261                         * been sent. but we promise to finish this function
 262                         * for a caller. Here we use FCP_TIMEOUT_MS for next
 263                         * interval. This is not in the specification.
 264                         */
 265                        t.state = STATE_PENDING;
 266                        goto deferred;
 267                } else if (t.state == STATE_COMPLETE) {
 268                        ret = t.response_size;
 269                        break;
 270                } else if (t.state == STATE_BUS_RESET) {
 271                        msleep(ERROR_DELAY_MS);
 272                } else if (++tries >= ERROR_RETRIES) {
 273                        dev_err(&t.unit->device, "FCP command timed out\n");
 274                        ret = -EIO;
 275                        break;
 276                }
 277        }
 278
 279        spin_lock_irq(&transactions_lock);
 280        list_del(&t.list);
 281        spin_unlock_irq(&transactions_lock);
 282
 283        return ret;
 284}
 285EXPORT_SYMBOL(fcp_avc_transaction);
 286
 287/**
 288 * fcp_bus_reset - inform the target handler about a bus reset
 289 * @unit: the unit that might be used by fcp_avc_transaction()
 290 *
 291 * This function must be called from the driver's .update handler to inform
 292 * the FCP transaction handler that a bus reset has happened.  Any pending FCP
 293 * transactions are retried.
 294 */
 295void fcp_bus_reset(struct fw_unit *unit)
 296{
 297        struct fcp_transaction *t;
 298
 299        spin_lock_irq(&transactions_lock);
 300        list_for_each_entry(t, &transactions, list) {
 301                if (t->unit == unit &&
 302                    (t->state == STATE_PENDING ||
 303                     t->state == STATE_DEFERRED)) {
 304                        t->state = STATE_BUS_RESET;
 305                        wake_up(&t->wait);
 306                }
 307        }
 308        spin_unlock_irq(&transactions_lock);
 309}
 310EXPORT_SYMBOL(fcp_bus_reset);
 311
 312/* checks whether the response matches the masked bytes in response_buffer */
 313static bool is_matching_response(struct fcp_transaction *transaction,
 314                                 const void *response, size_t length)
 315{
 316        const u8 *p1, *p2;
 317        unsigned int mask, i;
 318
 319        p1 = response;
 320        p2 = transaction->response_buffer;
 321        mask = transaction->response_match_bytes;
 322
 323        for (i = 0; ; ++i) {
 324                if ((mask & 1) && p1[i] != p2[i])
 325                        return false;
 326                mask >>= 1;
 327                if (!mask)
 328                        return true;
 329                if (--length == 0)
 330                        return false;
 331        }
 332}
 333
 334static void fcp_response(struct fw_card *card, struct fw_request *request,
 335                         int tcode, int destination, int source,
 336                         int generation, unsigned long long offset,
 337                         void *data, size_t length, void *callback_data)
 338{
 339        struct fcp_transaction *t;
 340        unsigned long flags;
 341
 342        if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC)
 343                return;
 344
 345        spin_lock_irqsave(&transactions_lock, flags);
 346        list_for_each_entry(t, &transactions, list) {
 347                struct fw_device *device = fw_parent_device(t->unit);
 348                if (device->card != card ||
 349                    device->generation != generation)
 350                        continue;
 351                smp_rmb(); /* node_id vs. generation */
 352                if (device->node_id != source)
 353                        continue;
 354
 355                if (t->state == STATE_PENDING &&
 356                    is_matching_response(t, data, length)) {
 357                        if (t->deferrable && *(const u8 *)data == 0x0f) {
 358                                t->state = STATE_DEFERRED;
 359                        } else {
 360                                t->state = STATE_COMPLETE;
 361                                t->response_size = min_t(unsigned int, length,
 362                                                         t->response_size);
 363                                memcpy(t->response_buffer, data,
 364                                       t->response_size);
 365                        }
 366                        wake_up(&t->wait);
 367                }
 368        }
 369        spin_unlock_irqrestore(&transactions_lock, flags);
 370}
 371
 372static struct fw_address_handler response_register_handler = {
 373        .length = 0x200,
 374        .address_callback = fcp_response,
 375};
 376
 377static int __init fcp_module_init(void)
 378{
 379        static const struct fw_address_region response_register_region = {
 380                .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
 381                .end = CSR_REGISTER_BASE + CSR_FCP_END,
 382        };
 383
 384        fw_core_add_address_handler(&response_register_handler,
 385                                    &response_register_region);
 386
 387        return 0;
 388}
 389
 390static void __exit fcp_module_exit(void)
 391{
 392        WARN_ON(!list_empty(&transactions));
 393        fw_core_remove_address_handler(&response_register_handler);
 394}
 395
 396module_init(fcp_module_init);
 397module_exit(fcp_module_exit);
 398