Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / drivers / media / video / pvrusb2 / pvrusb2-encoder.c
1 /*
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>
25 #include "pvrusb2-util.h"
26 #include "pvrusb2-encoder.h"
27 #include "pvrusb2-hdw-internal.h"
28 #include "pvrusb2-debug.h"
29
30
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
38 static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
39                                     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
79 static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
80                                    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
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,
126                             int cmd,
127                             int arg_cnt_send,
128                             int arg_cnt_recv,
129                             u32 *argp)
130 {
131         unsigned int poll_count;
132         int ret = 0;
133         unsigned int idx;
134         /* These sizes look to be limited by the FX2 firmware implementation */
135         u32 wrData[16];
136         u32 rdData[16];
137         struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
138
139
140         /*
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
172         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,
179                         (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
180                 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,
190                         (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
191                 return -EINVAL;
192         }
193
194
195         LOCK_TAKE(hdw->ctl_lock); do {
196
197                 wrData[0] = 0;
198                 wrData[1] = cmd;
199                 wrData[2] = 0;
200                 wrData[3] = 0x00060000;
201                 for (idx = 0; idx < arg_cnt_send; idx++) {
202                         wrData[idx+4] = argp[idx];
203                 }
204                 for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
205                         wrData[idx+4] = 0;
206                 }
207
208                 ret = pvr2_encoder_write_words(hdw,wrData,idx);
209                 if (ret) break;
210                 wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
211                 ret = pvr2_encoder_write_words(hdw,wrData,1);
212                 if (ret) break;
213                 poll_count = 0;
214                 while (1) {
215                         if (poll_count < 10000000) poll_count++;
216                         ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
217                         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);
230                                 for (idx = 4; idx < arg_cnt_send; 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                         }
244                 }
245                 if (ret) break;
246                 wrData[0] = 0x7;
247                 ret = pvr2_encoder_read_words(
248                         hdw,0,rdData,
249                         sizeof(rdData)/sizeof(rdData[0]));
250                 if (ret) break;
251                 for (idx = 0; idx < arg_cnt_recv; idx++) {
252                         argp[idx] = rdData[idx+4];
253                 }
254
255                 wrData[0] = 0x0;
256                 ret = pvr2_encoder_write_words(hdw,wrData,1);
257                 if (ret) break;
258
259         } while(0); LOCK_GIVE(hdw->ctl_lock);
260
261         return ret;
262 }
263
264
265 static 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)",
278                         args,(unsigned int)(sizeof(data)/sizeof(data[0])));
279                 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
291 int pvr2_encoder_configure(struct pvr2_hdw *hdw)
292 {
293         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);
302
303         ret = 0;
304
305         if (!ret) ret = pvr2_encoder_vcmd(
306                 hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
307                 0xf0, 0xf0);
308
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);
313
314         if (!ret) ret = pvr2_encoder_vcmd(
315                 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
316                 0xffffffff,0,0,0,0);
317
318         if (ret) {
319                 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
320                            "Failed to configure cx32416");
321                 return ret;
322         }
323
324         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;
331         }
332
333         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;
349 }
350
351
352 int 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) {
364                 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
365                                            0x01,0x14);
366         } else if (hdw->config == pvr2_config_mpeg) {
367                 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
368                                            0,0x13);
369         } else {
370                 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
371                                            0,0x13);
372         }
373         if (!status) {
374                 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
375         }
376         return status;
377 }
378
379 int 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) {
387                 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
388                                            0x01,0x01,0x14);
389         } else if (hdw->config == pvr2_config_mpeg) {
390                 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
391                                            0x01,0,0x13);
392         } else {
393                 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
394                                            0x01,0,0x13);
395         }
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   */