blob: 2cc31695b435cadfc9053a0e4d97a77d5274e217 [file] [log] [blame]
Mike Iselyd8554972006-06-26 20:58:46 -03001/*
2 *
3 * $Id$
4 *
5 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
6 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <linux/device.h> // for linux/firmware.h
24#include <linux/firmware.h>
Mike Iselyd8554972006-06-26 20:58:46 -030025#include "pvrusb2-util.h"
26#include "pvrusb2-encoder.h"
27#include "pvrusb2-hdw-internal.h"
28#include "pvrusb2-debug.h"
29
Mike Iselyd8554972006-06-26 20:58:46 -030030
31
32/* Firmware mailbox flags - definitions found from ivtv */
33#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
34#define IVTV_MBOX_DRIVER_DONE 0x00000002
35#define IVTV_MBOX_DRIVER_BUSY 0x00000001
36
37
Mike Iselyeacbe7c2006-06-25 20:04:06 -030038static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
Mike Iselyd8554972006-06-26 20:58:46 -030039 const u32 *data, unsigned int dlen)
40{
41 unsigned int idx;
42 int ret;
43 unsigned int offs = 0;
44 unsigned int chunkCnt;
45
46 /*
47
48 Format: First byte must be 0x01. Remaining 32 bit words are
49 spread out into chunks of 7 bytes each, little-endian ordered,
50 offset at zero within each 2 blank bytes following and a
51 single byte that is 0x44 plus the offset of the word. Repeat
52 request for additional words, with offset adjusted
53 accordingly.
54
55 */
56 while (dlen) {
57 chunkCnt = 8;
58 if (chunkCnt > dlen) chunkCnt = dlen;
59 memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
60 hdw->cmd_buffer[0] = 0x01;
61 for (idx = 0; idx < chunkCnt; idx++) {
62 hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
63 PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
64 data[idx]);
65 }
66 ret = pvr2_send_request(hdw,
67 hdw->cmd_buffer,1+(chunkCnt*7),
68 0,0);
69 if (ret) return ret;
70 data += chunkCnt;
71 dlen -= chunkCnt;
72 offs += chunkCnt;
73 }
74
75 return 0;
76}
77
78
Mike Iselyeacbe7c2006-06-25 20:04:06 -030079static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
Mike Iselyd8554972006-06-26 20:58:46 -030080 u32 *data, unsigned int dlen)
81{
82 unsigned int idx;
83 int ret;
84 unsigned int offs = 0;
85 unsigned int chunkCnt;
86
87 /*
88
89 Format: First byte must be 0x02 (status check) or 0x28 (read
90 back block of 32 bit words). Next 6 bytes must be zero,
91 followed by a single byte of 0x44+offset for portion to be
92 read. Returned data is packed set of 32 bits words that were
93 read.
94
95 */
96
97 while (dlen) {
98 chunkCnt = 16;
99 if (chunkCnt > dlen) chunkCnt = dlen;
100 memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
101 hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
102 hdw->cmd_buffer[7] = 0x44 + offs;
103 ret = pvr2_send_request(hdw,
104 hdw->cmd_buffer,8,
105 hdw->cmd_buffer,chunkCnt * 4);
106 if (ret) return ret;
107
108 for (idx = 0; idx < chunkCnt; idx++) {
109 data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
110 }
111 data += chunkCnt;
112 dlen -= chunkCnt;
113 offs += chunkCnt;
114 }
115
116 return 0;
117}
118
119
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300120/* This prototype is set up to be compatible with the
121 cx2341x_mbox_func prototype in cx2341x.h, which should be in
122 kernels 2.6.18 or later. We do this so that we can enable
123 cx2341x.ko to write to our encoder (by handing it a pointer to this
124 function). For earlier kernels this doesn't really matter. */
125static int pvr2_encoder_cmd(void *ctxt,
126 int cmd,
127 int arg_cnt_send,
128 int arg_cnt_recv,
129 u32 *argp)
Mike Iselyd8554972006-06-26 20:58:46 -0300130{
131 unsigned int poll_count;
132 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300133 unsigned int idx;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300134 /* These sizes look to be limited by the FX2 firmware implementation */
Mike Iselyd8554972006-06-26 20:58:46 -0300135 u32 wrData[16];
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300136 u32 rdData[16];
137 struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
Mike Iselyd8554972006-06-26 20:58:46 -0300138
Mike Iselyc05c0462006-06-25 20:04:25 -0300139
Mike Iselyd8554972006-06-26 20:58:46 -0300140 /*
141
142 The encoder seems to speak entirely using blocks 32 bit words.
143 In ivtv driver terms, this is a mailbox which we populate with
144 data and watch what the hardware does with it. The first word
145 is a set of flags used to control the transaction, the second
146 word is the command to execute, the third byte is zero (ivtv
147 driver suggests that this is some kind of return value), and
148 the fourth byte is a specified timeout (windows driver always
149 uses 0x00060000 except for one case when it is zero). All
150 successive words are the argument words for the command.
151
152 First, write out the entire set of words, with the first word
153 being zero.
154
155 Next, write out just the first word again, but set it to
156 IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
157 probably means "go").
158
159 Next, read back 16 words as status. Check the first word,
160 which should have IVTV_MBOX_FIRMWARE_DONE set. If however
161 that bit is not set, then the command isn't done so repeat the
162 read.
163
164 Next, read back 32 words and compare with the original
165 arugments. Hopefully they will match.
166
167 Finally, write out just the first word again, but set it to
168 0x0 this time (which probably means "idle").
169
170 */
171
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300172 if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
173 pvr2_trace(
174 PVR2_TRACE_ERROR_LEGS,
175 "Failed to write cx23416 command"
176 " - too many input arguments"
177 " (was given %u limit %u)",
178 arg_cnt_send,
Mauro Carvalho Chehabc78059f2006-06-27 00:03:43 -0300179 (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300180 return -EINVAL;
181 }
182
183 if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
184 pvr2_trace(
185 PVR2_TRACE_ERROR_LEGS,
186 "Failed to write cx23416 command"
187 " - too many return arguments"
188 " (was given %u limit %u)",
189 arg_cnt_recv,
Mauro Carvalho Chehabc78059f2006-06-27 00:03:43 -0300190 (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300191 return -EINVAL;
192 }
193
Mike Iselyd8554972006-06-26 20:58:46 -0300194
195 LOCK_TAKE(hdw->ctl_lock); do {
196
197 wrData[0] = 0;
198 wrData[1] = cmd;
199 wrData[2] = 0;
200 wrData[3] = 0x00060000;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300201 for (idx = 0; idx < arg_cnt_send; idx++) {
202 wrData[idx+4] = argp[idx];
Mike Iselyd8554972006-06-26 20:58:46 -0300203 }
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300204 for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
205 wrData[idx+4] = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300206 }
207
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300208 ret = pvr2_encoder_write_words(hdw,wrData,idx);
Mike Iselyd8554972006-06-26 20:58:46 -0300209 if (ret) break;
210 wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300211 ret = pvr2_encoder_write_words(hdw,wrData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300212 if (ret) break;
213 poll_count = 0;
214 while (1) {
215 if (poll_count < 10000000) poll_count++;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300216 ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300217 if (ret) break;
218 if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
219 break;
220 }
221 if (poll_count == 100) {
222 pvr2_trace(
223 PVR2_TRACE_ERROR_LEGS,
224 "***WARNING*** device's encoder"
225 " appears to be stuck"
226 " (status=0%08x)",rdData[0]);
227 pvr2_trace(
228 PVR2_TRACE_ERROR_LEGS,
229 "Encoder command: 0x%02x",cmd);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300230 for (idx = 4; idx < arg_cnt_send; idx++) {
Mike Iselyd8554972006-06-26 20:58:46 -0300231 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 }
244 }
245 if (ret) break;
246 wrData[0] = 0x7;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300247 ret = pvr2_encoder_read_words(
248 hdw,0,rdData,
249 sizeof(rdData)/sizeof(rdData[0]));
Mike Iselyd8554972006-06-26 20:58:46 -0300250 if (ret) break;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300251 for (idx = 0; idx < arg_cnt_recv; idx++) {
252 argp[idx] = rdData[idx+4];
Mike Iselyd8554972006-06-26 20:58:46 -0300253 }
254
255 wrData[0] = 0x0;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300256 ret = pvr2_encoder_write_words(hdw,wrData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300257 if (ret) break;
258
259 } while(0); LOCK_GIVE(hdw->ctl_lock);
260
261 return ret;
262}
263
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300264
265static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
266 int args, ...)
267{
268 va_list vl;
269 unsigned int idx;
270 u32 data[12];
271
272 if (args > sizeof(data)/sizeof(data[0])) {
273 pvr2_trace(
274 PVR2_TRACE_ERROR_LEGS,
275 "Failed to write cx23416 command"
276 " - too many arguments"
277 " (was given %u limit %u)",
Mauro Carvalho Chehabc78059f2006-06-27 00:03:43 -0300278 args,(unsigned int)(sizeof(data)/sizeof(data[0])));
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300279 return -EINVAL;
280 }
281
282 va_start(vl, args);
283 for (idx = 0; idx < args; idx++) {
284 data[idx] = va_arg(vl, u32);
285 }
286 va_end(vl);
287
288 return pvr2_encoder_cmd(hdw,cmd,args,0,data);
289}
290
Mike Iselyd8554972006-06-26 20:58:46 -0300291int pvr2_encoder_configure(struct pvr2_hdw *hdw)
292{
Mike Iselyb30d2442006-06-25 20:05:01 -0300293 int ret;
294 pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure"
295 " (cx2341x module)");
296 hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;
297 hdw->enc_ctl_state.width = hdw->res_hor_val;
298 hdw->enc_ctl_state.height = hdw->res_ver_val;
299 hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur &
300 (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ?
301 0 : 1);
Mike Iselyd8554972006-06-26 20:58:46 -0300302
Mike Iselyb30d2442006-06-25 20:05:01 -0300303 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300304
Mike Iselyb30d2442006-06-25 20:05:01 -0300305 if (!ret) ret = pvr2_encoder_vcmd(
306 hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
307 0xf0, 0xf0);
Mike Iselyd8554972006-06-26 20:58:46 -0300308
309 /* setup firmware to notify us about some events (don't know why...) */
Mike Iselyb30d2442006-06-25 20:05:01 -0300310 if (!ret) ret = pvr2_encoder_vcmd(
311 hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
312 0, 0, 0x10000000, 0xffffffff);
Mike Iselyd8554972006-06-26 20:58:46 -0300313
Mike Iselyb30d2442006-06-25 20:05:01 -0300314 if (!ret) ret = pvr2_encoder_vcmd(
315 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
316 0xffffffff,0,0,0,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300317
Mike Iselyb30d2442006-06-25 20:05:01 -0300318 if (ret) {
319 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
320 "Failed to configure cx32416");
321 return ret;
Mike Iselyd8554972006-06-26 20:58:46 -0300322 }
323
Mike Iselyb30d2442006-06-25 20:05:01 -0300324 ret = cx2341x_update(hdw,pvr2_encoder_cmd,
325 (hdw->enc_cur_valid ? &hdw->enc_cur_state : 0),
326 &hdw->enc_ctl_state);
327 if (ret) {
328 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
329 "Error from cx2341x module code=%d",ret);
330 return ret;
Mike Iselyd8554972006-06-26 20:58:46 -0300331 }
332
Mike Iselyb30d2442006-06-25 20:05:01 -0300333 ret = 0;
334
335 if (!ret) ret = pvr2_encoder_vcmd(
336 hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
337
338 if (ret) {
339 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
340 "Failed to initialize cx32416 video input");
341 return ret;
342 }
343
344 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
345 memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
346 sizeof(struct cx2341x_mpeg_params));
347 hdw->enc_cur_valid = !0;
348 return 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300349}
350
Mike Iselyb30d2442006-06-25 20:05:01 -0300351
Mike Iselyd8554972006-06-26 20:58:46 -0300352int pvr2_encoder_start(struct pvr2_hdw *hdw)
353{
354 int status;
355
356 /* unmask some interrupts */
357 pvr2_write_register(hdw, 0x0048, 0xbfffffff);
358
359 /* change some GPIO data */
360 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
361 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
362
363 if (hdw->config == pvr2_config_vbi) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300364 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
365 0x01,0x14);
Mike Iselyd8554972006-06-26 20:58:46 -0300366 } else if (hdw->config == pvr2_config_mpeg) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300367 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
368 0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300369 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300370 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
371 0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300372 }
373 if (!status) {
374 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
375 }
376 return status;
377}
378
379int pvr2_encoder_stop(struct pvr2_hdw *hdw)
380{
381 int status;
382
383 /* mask all interrupts */
384 pvr2_write_register(hdw, 0x0048, 0xffffffff);
385
386 if (hdw->config == pvr2_config_vbi) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300387 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
388 0x01,0x01,0x14);
Mike Iselyd8554972006-06-26 20:58:46 -0300389 } else if (hdw->config == pvr2_config_mpeg) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300390 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
391 0x01,0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300392 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300393 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
394 0x01,0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300395 }
396
397 /* change some GPIO data */
398 /* Note: Bit d7 of dir appears to control the LED. So we shut it
399 off here. */
400 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
401 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
402
403 if (!status) {
404 hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
405 }
406 return status;
407}
408
409
410/*
411 Stuff for Emacs to see, in order to encourage consistent editing style:
412 *** Local Variables: ***
413 *** mode: c ***
414 *** fill-column: 70 ***
415 *** tab-width: 8 ***
416 *** c-basic-offset: 8 ***
417 *** End: ***
418 */