Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/motu/motu-transaction.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* motu-transaction.c - a part of driver for MOTU FireWire series
4
*
5
* Copyright (c) 2015-2017 Takashi Sakamoto <[email protected]>
6
*/
7
8
9
#include "motu.h"
10
11
#define SND_MOTU_ADDR_BASE 0xfffff0000000ULL
12
#define ASYNC_ADDR_HI 0x0b04
13
#define ASYNC_ADDR_LO 0x0b08
14
15
int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
16
size_t size)
17
{
18
int tcode;
19
20
if (size % sizeof(__be32) > 0 || size <= 0)
21
return -EINVAL;
22
if (size == sizeof(__be32))
23
tcode = TCODE_READ_QUADLET_REQUEST;
24
else
25
tcode = TCODE_READ_BLOCK_REQUEST;
26
27
return snd_fw_transaction(motu->unit, tcode,
28
SND_MOTU_ADDR_BASE + offset, reg, size, 0);
29
}
30
31
int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
32
size_t size)
33
{
34
int tcode;
35
36
if (size % sizeof(__be32) > 0 || size <= 0)
37
return -EINVAL;
38
if (size == sizeof(__be32))
39
tcode = TCODE_WRITE_QUADLET_REQUEST;
40
else
41
tcode = TCODE_WRITE_BLOCK_REQUEST;
42
43
return snd_fw_transaction(motu->unit, tcode,
44
SND_MOTU_ADDR_BASE + offset, reg, size, 0);
45
}
46
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)
51
{
52
struct snd_motu *motu = callback_data;
53
__be32 *buf = (__be32 *)data;
54
55
if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
56
fw_send_response(card, request, RCODE_COMPLETE);
57
return;
58
}
59
60
if (offset != motu->async_handler.offset || length != 4) {
61
fw_send_response(card, request, RCODE_ADDRESS_ERROR);
62
return;
63
}
64
65
scoped_guard(spinlock_irqsave, &motu->lock) {
66
motu->msg = be32_to_cpu(*buf);
67
}
68
69
fw_send_response(card, request, RCODE_COMPLETE);
70
71
wake_up(&motu->hwdep_wait);
72
}
73
74
int snd_motu_transaction_reregister(struct snd_motu *motu)
75
{
76
struct fw_device *device = fw_parent_device(motu->unit);
77
__be32 data;
78
int err;
79
80
if (motu->async_handler.callback_data == NULL)
81
return -EINVAL;
82
83
/* Register messaging address. Block transaction is not allowed. */
84
data = cpu_to_be32((device->card->node_id << 16) |
85
(motu->async_handler.offset >> 32));
86
err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
87
sizeof(data));
88
if (err < 0)
89
return err;
90
91
data = cpu_to_be32(motu->async_handler.offset);
92
return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
93
sizeof(data));
94
}
95
96
int snd_motu_transaction_register(struct snd_motu *motu)
97
{
98
static const struct fw_address_region resp_register_region = {
99
.start = 0xffffe0000000ull,
100
.end = 0xffffe000ffffull,
101
};
102
int err;
103
104
/* Perhaps, 4 byte messages are transferred. */
105
motu->async_handler.length = 4;
106
motu->async_handler.address_callback = handle_message;
107
motu->async_handler.callback_data = motu;
108
109
err = fw_core_add_address_handler(&motu->async_handler,
110
&resp_register_region);
111
if (err < 0)
112
return err;
113
114
err = snd_motu_transaction_reregister(motu);
115
if (err < 0) {
116
fw_core_remove_address_handler(&motu->async_handler);
117
motu->async_handler.address_callback = NULL;
118
}
119
120
return err;
121
}
122
123
void snd_motu_transaction_unregister(struct snd_motu *motu)
124
{
125
__be32 data;
126
127
if (motu->async_handler.address_callback != NULL)
128
fw_core_remove_address_handler(&motu->async_handler);
129
motu->async_handler.address_callback = NULL;
130
131
/* Unregister the address. */
132
data = cpu_to_be32(0x00000000);
133
snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
134
snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
135
}
136
137