ALSA: bebob: Add commands and connections/streams management
[linux-block.git] / sound / firewire / bebob / bebob_command.c
CommitLineData
eb7b3a05
TS
1/*
2 * bebob_command.c - driver for BeBoB based devices
3 *
4 * Copyright (c) 2013-2014 Takashi Sakamoto
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include "./bebob.h"
10
11static inline void
12avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr)
13{
14 buf[1] = addr[0];
15 memcpy(buf + 4, addr + 1, 5);
16}
17
18static inline void
19avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr,
20 unsigned int itype)
21{
22 buf[0] = 0x01; /* AV/C STATUS */
23 buf[2] = 0x02; /* AV/C GENERAL PLUG INFO */
24 buf[3] = 0xc0; /* BridgeCo extension */
25 avc_bridgeco_fill_extension_addr(buf, addr);
26 buf[9] = itype; /* info type */
27}
28
29int avc_bridgeco_get_plug_type(struct fw_unit *unit,
30 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
31 enum avc_bridgeco_plug_type *type)
32{
33 u8 *buf;
34 int err;
35
36 buf = kzalloc(12, GFP_KERNEL);
37 if (buf == NULL)
38 return -ENOMEM;
39
40 /* Info type is 'plug type'. */
41 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00);
42
43 err = fcp_avc_transaction(unit, buf, 12, buf, 12,
44 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
45 BIT(6) | BIT(7) | BIT(9));
46 if ((err >= 0) && (err < 8))
47 err = -EIO;
48 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
49 err = -ENOSYS;
50 else if (buf[0] == 0x0a) /* REJECTED */
51 err = -EINVAL;
52 else if (buf[0] == 0x0b) /* IN TRANSITION */
53 err = -EAGAIN;
54 if (err < 0)
55 goto end;
56
57 *type = buf[10];
58 err = 0;
59end:
60 kfree(buf);
61 return err;
62}
63
64int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
65 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
66 u8 *buf, unsigned int len)
67{
68 int err;
69
70 /* Info type is 'channel position'. */
71 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03);
72
73 err = fcp_avc_transaction(unit, buf, 12, buf, 256,
74 BIT(1) | BIT(2) | BIT(3) | BIT(4) |
75 BIT(5) | BIT(6) | BIT(7) | BIT(9));
76 if ((err >= 0) && (err < 8))
77 err = -EIO;
78 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
79 err = -ENOSYS;
80 else if (buf[0] == 0x0a) /* REJECTED */
81 err = -EINVAL;
82 else if (buf[0] == 0x0b) /* IN TRANSITION */
83 err = -EAGAIN;
84 if (err < 0)
85 goto end;
86
87 /* Pick up specific data. */
88 memmove(buf, buf + 10, err - 10);
89 err = 0;
90end:
91 return err;
92}
93
94int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
95 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
96 unsigned int id, u8 *type)
97{
98 u8 *buf;
99 int err;
100
101 /* section info includes charactors but this module don't need it */
102 buf = kzalloc(12, GFP_KERNEL);
103 if (buf == NULL)
104 return -ENOMEM;
105
106 /* Info type is 'section info'. */
107 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07);
108 buf[10] = 0xff & ++id; /* section id */
109
110 err = fcp_avc_transaction(unit, buf, 12, buf, 12,
111 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
112 BIT(6) | BIT(7) | BIT(9) | BIT(10));
113 if ((err >= 0) && (err < 8))
114 err = -EIO;
115 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
116 err = -ENOSYS;
117 else if (buf[0] == 0x0a) /* REJECTED */
118 err = -EINVAL;
119 else if (buf[0] == 0x0b) /* IN TRANSITION */
120 err = -EAGAIN;
121 if (err < 0)
122 goto end;
123
124 *type = buf[11];
125 err = 0;
126end:
127 kfree(buf);
128 return err;
129}
130
131int avc_bridgeco_get_plug_input(struct fw_unit *unit,
132 u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
133{
134 int err;
135 u8 *buf;
136
137 buf = kzalloc(18, GFP_KERNEL);
138 if (buf == NULL)
139 return -ENOMEM;
140
141 /* Info type is 'plug input'. */
142 avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05);
143
144 err = fcp_avc_transaction(unit, buf, 16, buf, 16,
145 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
146 BIT(6) | BIT(7));
147 if ((err >= 0) && (err < 8))
148 err = -EIO;
149 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
150 err = -ENOSYS;
151 else if (buf[0] == 0x0a) /* REJECTED */
152 err = -EINVAL;
153 else if (buf[0] == 0x0b) /* IN TRANSITION */
154 err = -EAGAIN;
155 if (err < 0)
156 goto end;
157
158 memcpy(input, buf + 10, 5);
159 err = 0;
160end:
161 kfree(buf);
162 return err;
163}
164
165int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
166 u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf,
167 unsigned int *len, unsigned int eid)
168{
169 int err;
170
171 /* check given buffer */
172 if ((buf == NULL) || (*len < 12)) {
173 err = -EINVAL;
174 goto end;
175 }
176
177 buf[0] = 0x01; /* AV/C STATUS */
178 buf[2] = 0x2f; /* AV/C STREAM FORMAT SUPPORT */
179 buf[3] = 0xc1; /* Bridgeco extension - List Request */
180 avc_bridgeco_fill_extension_addr(buf, addr);
181 buf[10] = 0xff & eid; /* Entry ID */
182
183 err = fcp_avc_transaction(unit, buf, 12, buf, *len,
184 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
185 BIT(6) | BIT(7) | BIT(10));
186 if ((err >= 0) && (err < 12))
187 err = -EIO;
188 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
189 err = -ENOSYS;
190 else if (buf[0] == 0x0a) /* REJECTED */
191 err = -EINVAL;
192 else if (buf[0] == 0x0b) /* IN TRANSITION */
193 err = -EAGAIN;
194 else if (buf[10] != eid)
195 err = -EIO;
196 if (err < 0)
197 goto end;
198
199 /* Pick up 'stream format info'. */
200 memmove(buf, buf + 11, err - 11);
201 *len = err - 11;
202 err = 0;
203end:
204 return err;
205}