Commit | Line | Data |
---|---|---|
5b59d809 TS |
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 | ||
11 | int 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 | ||
51 | int 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; | |
104 | end: | |
105 | return err; | |
106 | } | |
107 | ||
108 | int 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; | |
150 | end: | |
151 | kfree(buf); | |
152 | return err; | |
153 | } |