5 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
6 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
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
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.
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
23 #include <linux/device.h> // for linux/firmware.h
24 #include <linux/firmware.h>
25 #include "pvrusb2-util.h"
26 #include "pvrusb2-encoder.h"
27 #include "pvrusb2-hdw-internal.h"
28 #include "pvrusb2-debug.h"
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
38 static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
39 const u32 *data, unsigned int dlen)
43 unsigned int offs = 0;
44 unsigned int chunkCnt;
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
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),
66 ret = pvr2_send_request(hdw,
67 hdw->cmd_buffer,1+(chunkCnt*7),
79 static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
80 u32 *data, unsigned int dlen)
84 unsigned int offs = 0;
85 unsigned int chunkCnt;
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
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,
105 hdw->cmd_buffer,chunkCnt * 4);
108 for (idx = 0; idx < chunkCnt; idx++) {
109 data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
120 /* 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. */
125 static int pvr2_encoder_cmd(void *ctxt,
131 unsigned int poll_count;
134 /* These sizes look to be limited by the FX2 firmware implementation */
137 struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
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.
152 First, write out the entire set of words, with the first word
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").
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
164 Next, read back 32 words and compare with the original
165 arugments. Hopefully they will match.
167 Finally, write out just the first word again, but set it to
168 0x0 this time (which probably means "idle").
172 if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
174 PVR2_TRACE_ERROR_LEGS,
175 "Failed to write cx23416 command"
176 " - too many input arguments"
177 " (was given %u limit %u)",
179 (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
183 if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
185 PVR2_TRACE_ERROR_LEGS,
186 "Failed to write cx23416 command"
187 " - too many return arguments"
188 " (was given %u limit %u)",
190 (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
195 LOCK_TAKE(hdw->ctl_lock); do {
200 wrData[3] = 0x00060000;
201 for (idx = 0; idx < arg_cnt_send; idx++) {
202 wrData[idx+4] = argp[idx];
204 for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
208 ret = pvr2_encoder_write_words(hdw,wrData,idx);
210 wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
211 ret = pvr2_encoder_write_words(hdw,wrData,1);
215 if (poll_count < 10000000) poll_count++;
216 ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
218 if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
221 if (poll_count == 100) {
223 PVR2_TRACE_ERROR_LEGS,
224 "***WARNING*** device's encoder"
225 " appears to be stuck"
226 " (status=0%08x)",rdData[0]);
228 PVR2_TRACE_ERROR_LEGS,
229 "Encoder command: 0x%02x",cmd);
230 for (idx = 4; idx < arg_cnt_send; idx++) {
232 PVR2_TRACE_ERROR_LEGS,
233 "Encoder arg%d: 0x%08x",
237 PVR2_TRACE_ERROR_LEGS,
240 " this is a bad idea...");
247 ret = pvr2_encoder_read_words(
249 sizeof(rdData)/sizeof(rdData[0]));
251 for (idx = 0; idx < arg_cnt_recv; idx++) {
252 argp[idx] = rdData[idx+4];
256 ret = pvr2_encoder_write_words(hdw,wrData,1);
259 } while(0); LOCK_GIVE(hdw->ctl_lock);
265 static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
272 if (args > sizeof(data)/sizeof(data[0])) {
274 PVR2_TRACE_ERROR_LEGS,
275 "Failed to write cx23416 command"
276 " - too many arguments"
277 " (was given %u limit %u)",
278 args,(unsigned int)(sizeof(data)/sizeof(data[0])));
283 for (idx = 0; idx < args; idx++) {
284 data[idx] = va_arg(vl, u32);
288 return pvr2_encoder_cmd(hdw,cmd,args,0,data);
291 int pvr2_encoder_configure(struct pvr2_hdw *hdw)
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)) ?
305 if (!ret) ret = pvr2_encoder_vcmd(
306 hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
309 /* setup firmware to notify us about some events (don't know why...) */
310 if (!ret) ret = pvr2_encoder_vcmd(
311 hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
312 0, 0, 0x10000000, 0xffffffff);
314 if (!ret) ret = pvr2_encoder_vcmd(
315 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
319 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
320 "Failed to configure cx32416");
324 ret = cx2341x_update(hdw,pvr2_encoder_cmd,
325 (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
326 &hdw->enc_ctl_state);
328 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
329 "Error from cx2341x module code=%d",ret);
335 if (!ret) ret = pvr2_encoder_vcmd(
336 hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
339 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
340 "Failed to initialize cx32416 video input");
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;
352 int pvr2_encoder_start(struct pvr2_hdw *hdw)
356 /* unmask some interrupts */
357 pvr2_write_register(hdw, 0x0048, 0xbfffffff);
359 /* change some GPIO data */
360 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
361 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
363 if (hdw->config == pvr2_config_vbi) {
364 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
366 } else if (hdw->config == pvr2_config_mpeg) {
367 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
370 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
374 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
379 int pvr2_encoder_stop(struct pvr2_hdw *hdw)
383 /* mask all interrupts */
384 pvr2_write_register(hdw, 0x0048, 0xffffffff);
386 if (hdw->config == pvr2_config_vbi) {
387 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
389 } else if (hdw->config == pvr2_config_mpeg) {
390 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
393 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
397 /* change some GPIO data */
398 /* Note: Bit d7 of dir appears to control the LED. So we shut it
400 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
401 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
404 hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
411 Stuff for Emacs to see, in order to encourage consistent editing style:
412 *** Local Variables: ***
414 *** fill-column: 70 ***
416 *** c-basic-offset: 8 ***