1/*
2 * oxfw_command.c - a part of driver for OXFW970/971 based devices
3 *
4 * Copyright (c) 2014 Takashi Sakamoto
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include "oxfw.h"
10
11int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir,
12			  unsigned int pid, u8 *format, unsigned int len)
13{
14	u8 *buf;
15	int err;
16
17	buf = kmalloc(len + 10, GFP_KERNEL);
18	if (buf == NULL)
19		return -ENOMEM;
20
21	buf[0] = 0x00;		/* CONTROL */
22	buf[1] = 0xff;		/* UNIT */
23	buf[2] = 0xbf;		/* EXTENDED STREAM FORMAT INFORMATION */
24	buf[3] = 0xc0;		/* SINGLE subfunction */
25	buf[4] = dir;		/* Plug Direction */
26	buf[5] = 0x00;		/* UNIT */
27	buf[6] = 0x00;		/* PCR (Isochronous Plug) */
28	buf[7] = 0xff & pid;	/* Plug ID */
29	buf[8] = 0xff;		/* Padding */
30	buf[9] = 0xff;		/* Support status in response */
31	memcpy(buf + 10, format, len);
32
33	/* do transaction and check buf[1-8] are the same against command */
34	err = fcp_avc_transaction(unit, buf, len + 10, buf, len + 10,
35				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
36				  BIT(6) | BIT(7) | BIT(8));
37	if ((err > 0) && (err < len + 10))
38		err = -EIO;
39	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
40		err = -ENOSYS;
41	else if (buf[0] == 0x0a) /* REJECTED */
42		err = -EINVAL;
43	else
44		err = 0;
45
46	kfree(buf);
47
48	return err;
49}
50
51int avc_stream_get_format(struct fw_unit *unit,
52			  enum avc_general_plug_dir dir, unsigned int pid,
53			  u8 *buf, unsigned int *len, unsigned int eid)
54{
55	unsigned int subfunc;
56	int err;
57
58	if (eid == 0xff)
59		subfunc = 0xc0;	/* SINGLE */
60	else
61		subfunc = 0xc1;	/* LIST */
62
63	buf[0] = 0x01;		/* STATUS */
64	buf[1] = 0xff;		/* UNIT */
65	buf[2] = 0xbf;		/* EXTENDED STREAM FORMAT INFORMATION */
66	buf[3] = subfunc;	/* SINGLE or LIST */
67	buf[4] = dir;		/* Plug Direction */
68	buf[5] = 0x00;		/* Unit */
69	buf[6] = 0x00;		/* PCR (Isochronous Plug) */
70	buf[7] = 0xff & pid;	/* Plug ID */
71	buf[8] = 0xff;		/* Padding */
72	buf[9] = 0xff;		/* support status in response */
73	buf[10] = 0xff & eid;	/* entry ID for LIST subfunction */
74	buf[11] = 0xff;		/* padding */
75
76	/* do transaction and check buf[1-7] are the same against command */
77	err = fcp_avc_transaction(unit, buf, 12, buf, *len,
78				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
79				  BIT(6) | BIT(7));
80	if ((err > 0) && (err < 10))
81		err = -EIO;
82	else if (buf[0] == 0x08)	/* NOT IMPLEMENTED */
83		err = -ENOSYS;
84	else if (buf[0] == 0x0a)	/* REJECTED */
85		err = -EINVAL;
86	else if (buf[0] == 0x0b)	/* IN TRANSITION */
87		err = -EAGAIN;
88	/* LIST subfunction has entry ID */
89	else if ((subfunc == 0xc1) && (buf[10] != eid))
90		err = -EIO;
91	if (err < 0)
92		goto end;
93
94	/* keep just stream format information */
95	if (subfunc == 0xc0) {
96		memmove(buf, buf + 10, err - 10);
97		*len = err - 10;
98	} else {
99		memmove(buf, buf + 11, err - 11);
100		*len = err - 11;
101	}
102
103	err = 0;
104end:
105	return err;
106}
107
108int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
109				enum avc_general_plug_dir dir,
110				unsigned short pid)
111{
112	unsigned int sfc;
113	u8 *buf;
114	int err;
115
116	for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {
117		if (amdtp_rate_table[sfc] == rate)
118			break;
119	}
120	if (sfc == CIP_SFC_COUNT)
121		return -EINVAL;
122
123	buf = kzalloc(8, GFP_KERNEL);
124	if (buf == NULL)
125		return -ENOMEM;
126
127	buf[0] = 0x02;		/* SPECIFIC INQUIRY */
128	buf[1] = 0xff;		/* UNIT */
129	if (dir == AVC_GENERAL_PLUG_DIR_IN)
130		buf[2] = 0x19;	/* INPUT PLUG SIGNAL FORMAT */
131	else
132		buf[2] = 0x18;	/* OUTPUT PLUG SIGNAL FORMAT */
133	buf[3] = 0xff & pid;	/* plug id */
134	buf[4] = 0x90;		/* EOH_1, Form_1, FMT. AM824 */
135	buf[5] = 0x07 & sfc;	/* FDF-hi. AM824, frequency */
136	buf[6] = 0xff;		/* FDF-mid. AM824, SYT hi (not used) */
137	buf[7] = 0xff;		/* FDF-low. AM824, SYT lo (not used) */
138
139	/* do transaction and check buf[1-5] are the same against command */
140	err = fcp_avc_transaction(unit, buf, 8, buf, 8,
141				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
142	if ((err > 0) && (err < 8))
143		err = -EIO;
144	else if (buf[0] == 0x08)	/* NOT IMPLEMENTED */
145		err = -ENOSYS;
146	if (err < 0)
147		goto end;
148
149	err = 0;
150end:
151	kfree(buf);
152	return err;
153}
154