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