1 // SPDX-License-Identifier: GPL-2.0-only
3 * motu-transaction.c - a part of driver for MOTU FireWire series
5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
11 #define SND_MOTU_ADDR_BASE 0xfffff0000000ULL
12 #define ASYNC_ADDR_HI 0x0b04
13 #define ASYNC_ADDR_LO 0x0b08
15 int snd_motu_transaction_read(struct snd_motu
*motu
, u32 offset
, __be32
*reg
,
20 if (size
% sizeof(__be32
) > 0 || size
<= 0)
22 if (size
== sizeof(__be32
))
23 tcode
= TCODE_READ_QUADLET_REQUEST
;
25 tcode
= TCODE_READ_BLOCK_REQUEST
;
27 return snd_fw_transaction(motu
->unit
, tcode
,
28 SND_MOTU_ADDR_BASE
+ offset
, reg
, size
, 0);
31 int snd_motu_transaction_write(struct snd_motu
*motu
, u32 offset
, __be32
*reg
,
36 if (size
% sizeof(__be32
) > 0 || size
<= 0)
38 if (size
== sizeof(__be32
))
39 tcode
= TCODE_WRITE_QUADLET_REQUEST
;
41 tcode
= TCODE_WRITE_BLOCK_REQUEST
;
43 return snd_fw_transaction(motu
->unit
, tcode
,
44 SND_MOTU_ADDR_BASE
+ offset
, reg
, size
, 0);
47 static void handle_message(struct fw_card
*card
, struct fw_request
*request
,
48 int tcode
, int destination
, int source
,
49 int generation
, unsigned long long offset
,
50 void *data
, size_t length
, void *callback_data
)
52 struct snd_motu
*motu
= callback_data
;
53 __be32
*buf
= (__be32
*)data
;
56 if (tcode
!= TCODE_WRITE_QUADLET_REQUEST
) {
57 fw_send_response(card
, request
, RCODE_COMPLETE
);
61 if (offset
!= motu
->async_handler
.offset
|| length
!= 4) {
62 fw_send_response(card
, request
, RCODE_ADDRESS_ERROR
);
66 spin_lock_irqsave(&motu
->lock
, flags
);
67 motu
->msg
= be32_to_cpu(*buf
);
68 spin_unlock_irqrestore(&motu
->lock
, flags
);
70 fw_send_response(card
, request
, RCODE_COMPLETE
);
72 wake_up(&motu
->hwdep_wait
);
75 int snd_motu_transaction_reregister(struct snd_motu
*motu
)
77 struct fw_device
*device
= fw_parent_device(motu
->unit
);
81 if (motu
->async_handler
.callback_data
== NULL
)
84 /* Register messaging address. Block transaction is not allowed. */
85 data
= cpu_to_be32((device
->card
->node_id
<< 16) |
86 (motu
->async_handler
.offset
>> 32));
87 err
= snd_motu_transaction_write(motu
, ASYNC_ADDR_HI
, &data
,
92 data
= cpu_to_be32(motu
->async_handler
.offset
);
93 return snd_motu_transaction_write(motu
, ASYNC_ADDR_LO
, &data
,
97 int snd_motu_transaction_register(struct snd_motu
*motu
)
99 static const struct fw_address_region resp_register_region
= {
100 .start
= 0xffffe0000000ull
,
101 .end
= 0xffffe000ffffull
,
105 /* Perhaps, 4 byte messages are transferred. */
106 motu
->async_handler
.length
= 4;
107 motu
->async_handler
.address_callback
= handle_message
;
108 motu
->async_handler
.callback_data
= motu
;
110 err
= fw_core_add_address_handler(&motu
->async_handler
,
111 &resp_register_region
);
115 err
= snd_motu_transaction_reregister(motu
);
117 fw_core_remove_address_handler(&motu
->async_handler
);
118 motu
->async_handler
.address_callback
= NULL
;
124 void snd_motu_transaction_unregister(struct snd_motu
*motu
)
128 if (motu
->async_handler
.address_callback
!= NULL
)
129 fw_core_remove_address_handler(&motu
->async_handler
);
130 motu
->async_handler
.address_callback
= NULL
;
132 /* Unregister the address. */
133 data
= cpu_to_be32(0x00000000);
134 snd_motu_transaction_write(motu
, ASYNC_ADDR_HI
, &data
, sizeof(data
));
135 snd_motu_transaction_write(motu
, ASYNC_ADDR_LO
, &data
, sizeof(data
));