Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * motu-transaction.c - a part of driver for MOTU FireWire series
0004  *
0005  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
0006  */
0007 
0008 
0009 #include "motu.h"
0010 
0011 #define SND_MOTU_ADDR_BASE  0xfffff0000000ULL
0012 #define ASYNC_ADDR_HI  0x0b04
0013 #define ASYNC_ADDR_LO  0x0b08
0014 
0015 int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
0016                   size_t size)
0017 {
0018     int tcode;
0019 
0020     if (size % sizeof(__be32) > 0 || size <= 0)
0021         return -EINVAL;
0022     if (size == sizeof(__be32))
0023         tcode = TCODE_READ_QUADLET_REQUEST;
0024     else
0025         tcode = TCODE_READ_BLOCK_REQUEST;
0026 
0027     return snd_fw_transaction(motu->unit, tcode,
0028                   SND_MOTU_ADDR_BASE + offset, reg, size, 0);
0029 }
0030 
0031 int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
0032                    size_t size)
0033 {
0034     int tcode;
0035 
0036     if (size % sizeof(__be32) > 0 || size <= 0)
0037         return -EINVAL;
0038     if (size == sizeof(__be32))
0039         tcode = TCODE_WRITE_QUADLET_REQUEST;
0040     else
0041         tcode = TCODE_WRITE_BLOCK_REQUEST;
0042 
0043     return snd_fw_transaction(motu->unit, tcode,
0044                   SND_MOTU_ADDR_BASE + offset, reg, size, 0);
0045 }
0046 
0047 static void handle_message(struct fw_card *card, struct fw_request *request,
0048                int tcode, int destination, int source,
0049                int generation, unsigned long long offset,
0050                void *data, size_t length, void *callback_data)
0051 {
0052     struct snd_motu *motu = callback_data;
0053     __be32 *buf = (__be32 *)data;
0054     unsigned long flags;
0055 
0056     if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
0057         fw_send_response(card, request, RCODE_COMPLETE);
0058         return;
0059     }
0060 
0061     if (offset != motu->async_handler.offset || length != 4) {
0062         fw_send_response(card, request, RCODE_ADDRESS_ERROR);
0063         return;
0064     }
0065 
0066     spin_lock_irqsave(&motu->lock, flags);
0067     motu->msg = be32_to_cpu(*buf);
0068     spin_unlock_irqrestore(&motu->lock, flags);
0069 
0070     fw_send_response(card, request, RCODE_COMPLETE);
0071 
0072     wake_up(&motu->hwdep_wait);
0073 }
0074 
0075 int snd_motu_transaction_reregister(struct snd_motu *motu)
0076 {
0077     struct fw_device *device = fw_parent_device(motu->unit);
0078     __be32 data;
0079     int err;
0080 
0081     if (motu->async_handler.callback_data == NULL)
0082         return -EINVAL;
0083 
0084     /* Register messaging address. Block transaction is not allowed. */
0085     data = cpu_to_be32((device->card->node_id << 16) |
0086                (motu->async_handler.offset >> 32));
0087     err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
0088                      sizeof(data));
0089     if (err < 0)
0090         return err;
0091 
0092     data = cpu_to_be32(motu->async_handler.offset);
0093     return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
0094                       sizeof(data));
0095 }
0096 
0097 int snd_motu_transaction_register(struct snd_motu *motu)
0098 {
0099     static const struct fw_address_region resp_register_region = {
0100         .start  = 0xffffe0000000ull,
0101         .end    = 0xffffe000ffffull,
0102     };
0103     int err;
0104 
0105     /* Perhaps, 4 byte messages are transferred. */
0106     motu->async_handler.length = 4;
0107     motu->async_handler.address_callback = handle_message;
0108     motu->async_handler.callback_data = motu;
0109 
0110     err = fw_core_add_address_handler(&motu->async_handler,
0111                       &resp_register_region);
0112     if (err < 0)
0113         return err;
0114 
0115     err = snd_motu_transaction_reregister(motu);
0116     if (err < 0) {
0117         fw_core_remove_address_handler(&motu->async_handler);
0118         motu->async_handler.address_callback = NULL;
0119     }
0120 
0121     return err;
0122 }
0123 
0124 void snd_motu_transaction_unregister(struct snd_motu *motu)
0125 {
0126     __be32 data;
0127 
0128     if (motu->async_handler.address_callback != NULL)
0129         fw_core_remove_address_handler(&motu->async_handler);
0130     motu->async_handler.address_callback = NULL;
0131 
0132     /* Unregister the address. */
0133     data = cpu_to_be32(0x00000000);
0134     snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
0135     snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
0136 }