linux/sound/firewire/digi00x/digi00x-transaction.c
<<
>>
Prefs
   1/*
   2 * digi00x-transaction.c - a part of driver for Digidesign Digi 002/003 family
   3 *
   4 * Copyright (c) 2014-2015 Takashi Sakamoto
   5 *
   6 * Licensed under the terms of the GNU General Public License, version 2.
   7 */
   8
   9#include <sound/asound.h>
  10#include "digi00x.h"
  11
  12static void handle_unknown_message(struct snd_dg00x *dg00x,
  13                                   unsigned long long offset, __be32 *buf)
  14{
  15        unsigned long flags;
  16
  17        spin_lock_irqsave(&dg00x->lock, flags);
  18        dg00x->msg = be32_to_cpu(*buf);
  19        spin_unlock_irqrestore(&dg00x->lock, flags);
  20
  21        wake_up(&dg00x->hwdep_wait);
  22}
  23
  24static void handle_message(struct fw_card *card, struct fw_request *request,
  25                           int tcode, int destination, int source,
  26                           int generation, unsigned long long offset,
  27                           void *data, size_t length, void *callback_data)
  28{
  29        struct snd_dg00x *dg00x = callback_data;
  30        __be32 *buf = (__be32 *)data;
  31
  32        fw_send_response(card, request, RCODE_COMPLETE);
  33
  34        if (offset == dg00x->async_handler.offset)
  35                handle_unknown_message(dg00x, offset, buf);
  36}
  37
  38int snd_dg00x_transaction_reregister(struct snd_dg00x *dg00x)
  39{
  40        struct fw_device *device = fw_parent_device(dg00x->unit);
  41        __be32 data[2];
  42
  43        /* Unknown. 4bytes. */
  44        data[0] = cpu_to_be32((device->card->node_id << 16) |
  45                              (dg00x->async_handler.offset >> 32));
  46        data[1] = cpu_to_be32(dg00x->async_handler.offset);
  47        return snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST,
  48                                  DG00X_ADDR_BASE + DG00X_OFFSET_MESSAGE_ADDR,
  49                                  &data, sizeof(data), 0);
  50}
  51
  52void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x)
  53{
  54        if (dg00x->async_handler.callback_data == NULL)
  55                return;
  56
  57        fw_core_remove_address_handler(&dg00x->async_handler);
  58
  59        dg00x->async_handler.callback_data = NULL;
  60}
  61
  62int snd_dg00x_transaction_register(struct snd_dg00x *dg00x)
  63{
  64        static const struct fw_address_region resp_register_region = {
  65                .start  = 0xffffe0000000ull,
  66                .end    = 0xffffe000ffffull,
  67        };
  68        int err;
  69
  70        dg00x->async_handler.length = 4;
  71        dg00x->async_handler.address_callback = handle_message;
  72        dg00x->async_handler.callback_data = dg00x;
  73
  74        err = fw_core_add_address_handler(&dg00x->async_handler,
  75                                          &resp_register_region);
  76        if (err < 0)
  77                return err;
  78
  79        err = snd_dg00x_transaction_reregister(dg00x);
  80        if (err < 0)
  81                snd_dg00x_transaction_unregister(dg00x);
  82
  83        return err;
  84}
  85