diff options
author | Mike Isely <isely@pobox.com> | 2007-01-28 13:41:12 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-02-21 10:35:12 -0500 |
commit | c43000ef0c9f21fff090ff3b5428ac31a41dbc99 (patch) | |
tree | f3744d934d4c887278ae3905da5c5219e456a72d | |
parent | 567d7115b9ce8145c166e3368bf31fe613451f77 (diff) |
V4L/DVB (5173): Pvrusb2: encoder comm protocol cleanup
Update the implementation of the communication protocol for operating
the encoder, using updated knowledge about the encoder.
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-encoder.c | 150 |
1 files changed, 92 insertions, 58 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index ee5eb26ad56d..7cd95e9f914d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c | |||
@@ -35,34 +35,41 @@ | |||
35 | #define IVTV_MBOX_DRIVER_DONE 0x00000002 | 35 | #define IVTV_MBOX_DRIVER_DONE 0x00000002 |
36 | #define IVTV_MBOX_DRIVER_BUSY 0x00000001 | 36 | #define IVTV_MBOX_DRIVER_BUSY 0x00000001 |
37 | 37 | ||
38 | #define MBOX_BASE 0x44 | ||
39 | |||
38 | 40 | ||
39 | static int pvr2_encoder_write_words(struct pvr2_hdw *hdw, | 41 | static int pvr2_encoder_write_words(struct pvr2_hdw *hdw, |
42 | unsigned int offs, | ||
40 | const u32 *data, unsigned int dlen) | 43 | const u32 *data, unsigned int dlen) |
41 | { | 44 | { |
42 | unsigned int idx; | 45 | unsigned int idx,addr; |
46 | unsigned int bAddr; | ||
43 | int ret; | 47 | int ret; |
44 | unsigned int offs = 0; | ||
45 | unsigned int chunkCnt; | 48 | unsigned int chunkCnt; |
46 | 49 | ||
47 | /* | 50 | /* |
48 | 51 | ||
49 | Format: First byte must be 0x01. Remaining 32 bit words are | 52 | Format: First byte must be 0x01. Remaining 32 bit words are |
50 | spread out into chunks of 7 bytes each, little-endian ordered, | 53 | spread out into chunks of 7 bytes each, with the first 4 bytes |
51 | offset at zero within each 2 blank bytes following and a | 54 | being the data word (little endian), and the next 3 bytes |
52 | single byte that is 0x44 plus the offset of the word. Repeat | 55 | being the address where that data word is to be written (big |
53 | request for additional words, with offset adjusted | 56 | endian). Repeat request for additional words, with offset |
54 | accordingly. | 57 | adjusted accordingly. |
55 | 58 | ||
56 | */ | 59 | */ |
57 | while (dlen) { | 60 | while (dlen) { |
58 | chunkCnt = 8; | 61 | chunkCnt = 8; |
59 | if (chunkCnt > dlen) chunkCnt = dlen; | 62 | if (chunkCnt > dlen) chunkCnt = dlen; |
60 | memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); | 63 | memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); |
61 | hdw->cmd_buffer[0] = FX2CMD_MEM_WRITE_DWORD; | 64 | bAddr = 0; |
65 | hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD; | ||
62 | for (idx = 0; idx < chunkCnt; idx++) { | 66 | for (idx = 0; idx < chunkCnt; idx++) { |
63 | hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs; | 67 | addr = idx + offs; |
64 | PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7), | 68 | hdw->cmd_buffer[bAddr+6] = (addr & 0xffu); |
65 | data[idx]); | 69 | hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu); |
70 | hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu); | ||
71 | PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]); | ||
72 | bAddr += 7; | ||
66 | } | 73 | } |
67 | ret = pvr2_send_request(hdw, | 74 | ret = pvr2_send_request(hdw, |
68 | hdw->cmd_buffer,1+(chunkCnt*7), | 75 | hdw->cmd_buffer,1+(chunkCnt*7), |
@@ -77,34 +84,42 @@ static int pvr2_encoder_write_words(struct pvr2_hdw *hdw, | |||
77 | } | 84 | } |
78 | 85 | ||
79 | 86 | ||
80 | static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl, | 87 | static int pvr2_encoder_read_words(struct pvr2_hdw *hdw, |
88 | unsigned int offs, | ||
81 | u32 *data, unsigned int dlen) | 89 | u32 *data, unsigned int dlen) |
82 | { | 90 | { |
83 | unsigned int idx; | 91 | unsigned int idx; |
84 | int ret; | 92 | int ret; |
85 | unsigned int offs = 0; | ||
86 | unsigned int chunkCnt; | 93 | unsigned int chunkCnt; |
87 | 94 | ||
88 | /* | 95 | /* |
89 | 96 | ||
90 | Format: First byte must be 0x02 (status check) or 0x28 (read | 97 | Format: First byte must be 0x02 (status check) or 0x28 (read |
91 | back block of 32 bit words). Next 6 bytes must be zero, | 98 | back block of 32 bit words). Next 6 bytes must be zero, |
92 | followed by a single byte of 0x44+offset for portion to be | 99 | followed by a single byte of MBOX_BASE+offset for portion to |
93 | read. Returned data is packed set of 32 bits words that were | 100 | be read. Returned data is packed set of 32 bits words that |
94 | read. | 101 | were read. |
95 | 102 | ||
96 | */ | 103 | */ |
97 | 104 | ||
98 | while (dlen) { | 105 | while (dlen) { |
99 | chunkCnt = 16; | 106 | chunkCnt = 16; |
100 | if (chunkCnt > dlen) chunkCnt = dlen; | 107 | if (chunkCnt > dlen) chunkCnt = dlen; |
101 | memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); | 108 | if (chunkCnt < 16) chunkCnt = 1; |
102 | hdw->cmd_buffer[0] = | 109 | hdw->cmd_buffer[0] = |
103 | (statusFl ? FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES); | 110 | ((chunkCnt == 1) ? |
104 | hdw->cmd_buffer[7] = 0x44 + offs; | 111 | FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES); |
112 | hdw->cmd_buffer[1] = 0; | ||
113 | hdw->cmd_buffer[2] = 0; | ||
114 | hdw->cmd_buffer[3] = 0; | ||
115 | hdw->cmd_buffer[4] = 0; | ||
116 | hdw->cmd_buffer[5] = ((offs>>16) & 0xffu); | ||
117 | hdw->cmd_buffer[6] = ((offs>>8) & 0xffu); | ||
118 | hdw->cmd_buffer[7] = (offs & 0xffu); | ||
105 | ret = pvr2_send_request(hdw, | 119 | ret = pvr2_send_request(hdw, |
106 | hdw->cmd_buffer,8, | 120 | hdw->cmd_buffer,8, |
107 | hdw->cmd_buffer,chunkCnt * 4); | 121 | hdw->cmd_buffer, |
122 | (chunkCnt == 1 ? 4 : 16 * 4)); | ||
108 | if (ret) return ret; | 123 | if (ret) return ret; |
109 | 124 | ||
110 | for (idx = 0; idx < chunkCnt; idx++) { | 125 | for (idx = 0; idx < chunkCnt; idx++) { |
@@ -131,6 +146,8 @@ static int pvr2_encoder_cmd(void *ctxt, | |||
131 | u32 *argp) | 146 | u32 *argp) |
132 | { | 147 | { |
133 | unsigned int poll_count; | 148 | unsigned int poll_count; |
149 | unsigned int try_count = 0; | ||
150 | int retry_flag; | ||
134 | int ret = 0; | 151 | int ret = 0; |
135 | unsigned int idx; | 152 | unsigned int idx; |
136 | /* These sizes look to be limited by the FX2 firmware implementation */ | 153 | /* These sizes look to be limited by the FX2 firmware implementation */ |
@@ -142,14 +159,15 @@ static int pvr2_encoder_cmd(void *ctxt, | |||
142 | /* | 159 | /* |
143 | 160 | ||
144 | The encoder seems to speak entirely using blocks 32 bit words. | 161 | The encoder seems to speak entirely using blocks 32 bit words. |
145 | In ivtv driver terms, this is a mailbox which we populate with | 162 | In ivtv driver terms, this is a mailbox at MBOX_BASE which we |
146 | data and watch what the hardware does with it. The first word | 163 | populate with data and watch what the hardware does with it. |
147 | is a set of flags used to control the transaction, the second | 164 | The first word is a set of flags used to control the |
148 | word is the command to execute, the third byte is zero (ivtv | 165 | transaction, the second word is the command to execute, the |
149 | driver suggests that this is some kind of return value), and | 166 | third byte is zero (ivtv driver suggests that this is some |
150 | the fourth byte is a specified timeout (windows driver always | 167 | kind of return value), and the fourth byte is a specified |
151 | uses 0x00060000 except for one case when it is zero). All | 168 | timeout (windows driver always uses 0x00060000 except for one |
152 | successive words are the argument words for the command. | 169 | case when it is zero). All successive words are the argument |
170 | words for the command. | ||
153 | 171 | ||
154 | First, write out the entire set of words, with the first word | 172 | First, write out the entire set of words, with the first word |
155 | being zero. | 173 | being zero. |
@@ -158,13 +176,10 @@ static int pvr2_encoder_cmd(void *ctxt, | |||
158 | IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which | 176 | IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which |
159 | probably means "go"). | 177 | probably means "go"). |
160 | 178 | ||
161 | Next, read back 16 words as status. Check the first word, | 179 | Next, read back the return count words. Check the first word, |
162 | which should have IVTV_MBOX_FIRMWARE_DONE set. If however | 180 | which should have IVTV_MBOX_FIRMWARE_DONE set. If however |
163 | that bit is not set, then the command isn't done so repeat the | 181 | that bit is not set, then the command isn't done so repeat the |
164 | read. | 182 | read until it is set. |
165 | |||
166 | Next, read back 32 words and compare with the original | ||
167 | arugments. Hopefully they will match. | ||
168 | 183 | ||
169 | Finally, write out just the first word again, but set it to | 184 | Finally, write out just the first word again, but set it to |
170 | 0x0 this time (which probably means "idle"). | 185 | 0x0 this time (which probably means "idle"). |
@@ -194,6 +209,9 @@ static int pvr2_encoder_cmd(void *ctxt, | |||
194 | 209 | ||
195 | LOCK_TAKE(hdw->ctl_lock); do { | 210 | LOCK_TAKE(hdw->ctl_lock); do { |
196 | 211 | ||
212 | retry_flag = 0; | ||
213 | try_count++; | ||
214 | ret = 0; | ||
197 | wrData[0] = 0; | 215 | wrData[0] = 0; |
198 | wrData[1] = cmd; | 216 | wrData[1] = cmd; |
199 | wrData[2] = 0; | 217 | wrData[2] = 0; |
@@ -205,54 +223,70 @@ static int pvr2_encoder_cmd(void *ctxt, | |||
205 | wrData[idx+4] = 0; | 223 | wrData[idx+4] = 0; |
206 | } | 224 | } |
207 | 225 | ||
208 | ret = pvr2_encoder_write_words(hdw,wrData,idx); | 226 | ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx); |
209 | if (ret) break; | 227 | if (ret) break; |
210 | wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY; | 228 | wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY; |
211 | ret = pvr2_encoder_write_words(hdw,wrData,1); | 229 | ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1); |
212 | if (ret) break; | 230 | if (ret) break; |
213 | poll_count = 0; | 231 | poll_count = 0; |
214 | while (1) { | 232 | while (1) { |
215 | if (poll_count < 10000000) poll_count++; | 233 | poll_count++; |
216 | ret = pvr2_encoder_read_words(hdw,!0,rdData,1); | 234 | ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData, |
217 | if (ret) break; | 235 | arg_cnt_recv+4); |
236 | if (ret) { | ||
237 | break; | ||
238 | } | ||
218 | if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) { | 239 | if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) { |
219 | break; | 240 | break; |
220 | } | 241 | } |
221 | if (poll_count == 100) { | 242 | if (rdData[0] && (poll_count < 1000)) continue; |
243 | if (!rdData[0]) { | ||
244 | retry_flag = !0; | ||
245 | pvr2_trace( | ||
246 | PVR2_TRACE_ERROR_LEGS, | ||
247 | "Encoder timed out waiting for us" | ||
248 | "; arranging to retry"); | ||
249 | } else { | ||
222 | pvr2_trace( | 250 | pvr2_trace( |
223 | PVR2_TRACE_ERROR_LEGS, | 251 | PVR2_TRACE_ERROR_LEGS, |
224 | "***WARNING*** device's encoder" | 252 | "***WARNING*** device's encoder" |
225 | " appears to be stuck" | 253 | " appears to be stuck" |
226 | " (status=0%08x)",rdData[0]); | 254 | " (status=0%08x)",rdData[0]); |
255 | } | ||
256 | pvr2_trace( | ||
257 | PVR2_TRACE_ERROR_LEGS, | ||
258 | "Encoder command: 0x%02x",cmd); | ||
259 | for (idx = 4; idx < arg_cnt_send; idx++) { | ||
227 | pvr2_trace( | 260 | pvr2_trace( |
228 | PVR2_TRACE_ERROR_LEGS, | 261 | PVR2_TRACE_ERROR_LEGS, |
229 | "Encoder command: 0x%02x",cmd); | 262 | "Encoder arg%d: 0x%08x", |
230 | for (idx = 4; idx < arg_cnt_send; idx++) { | 263 | idx-3,wrData[idx]); |
231 | pvr2_trace( | ||
232 | PVR2_TRACE_ERROR_LEGS, | ||
233 | "Encoder arg%d: 0x%08x", | ||
234 | idx-3,wrData[idx]); | ||
235 | } | ||
236 | pvr2_trace( | ||
237 | PVR2_TRACE_ERROR_LEGS, | ||
238 | "Giving up waiting." | ||
239 | " It is likely that" | ||
240 | " this is a bad idea..."); | ||
241 | ret = -EBUSY; | ||
242 | break; | ||
243 | } | 264 | } |
265 | ret = -EBUSY; | ||
266 | break; | ||
267 | } | ||
268 | if (retry_flag) { | ||
269 | if (try_count < 20) continue; | ||
270 | pvr2_trace( | ||
271 | PVR2_TRACE_ERROR_LEGS, | ||
272 | "Too many retries..."); | ||
273 | ret = -EBUSY; | ||
274 | } | ||
275 | if (ret) { | ||
276 | pvr2_trace( | ||
277 | PVR2_TRACE_ERROR_LEGS, | ||
278 | "Giving up on command." | ||
279 | " It is likely that" | ||
280 | " this is a bad idea..."); | ||
281 | break; | ||
244 | } | 282 | } |
245 | if (ret) break; | ||
246 | wrData[0] = 0x7; | 283 | wrData[0] = 0x7; |
247 | ret = pvr2_encoder_read_words( | ||
248 | hdw,0,rdData, ARRAY_SIZE(rdData)); | ||
249 | if (ret) break; | ||
250 | for (idx = 0; idx < arg_cnt_recv; idx++) { | 284 | for (idx = 0; idx < arg_cnt_recv; idx++) { |
251 | argp[idx] = rdData[idx+4]; | 285 | argp[idx] = rdData[idx+4]; |
252 | } | 286 | } |
253 | 287 | ||
254 | wrData[0] = 0x0; | 288 | wrData[0] = 0x0; |
255 | ret = pvr2_encoder_write_words(hdw,wrData,1); | 289 | ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1); |
256 | if (ret) break; | 290 | if (ret) break; |
257 | 291 | ||
258 | } while(0); LOCK_GIVE(hdw->ctl_lock); | 292 | } while(0); LOCK_GIVE(hdw->ctl_lock); |