Comment out the correct #endif directive.
[mplayer/greg.git] / vidix / ivtv_vid.c
blob5c4bde970423ae846ad71c597ae2091c178b5168
1 /**
2 VIDIX driver for Hauppauge PVR 350.
4 Copyright 2007 Lutz Koschorreck.
6 Based on genfb_vid.c and ivtv_xv.c
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, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 09.05.2007 Lutz Koschorreck
23 First version: Tested with ivtv-0.10.1, xine-ui-0.99.5, xine-lib-1.1.6
24 20.05.2007 Lutz Koschorreck
25 Some Scaling and zooming problems fixed. By default the vidix driver now
26 controlls the setting of alphablending. So there is no need to use
27 ivtvfbctl anymore. To disable this feature set the following environment
28 variable:VIDIXIVTVALPHA=disable. Special thanx to Ian Armstrong.
29 23.07.2007 Lutz Koschorreck
30 Support for 2.6.22 kernel added. PCI scan added.
31 07.10.2007 Lutz Koschorreck
32 Restore old alpha value correctly. Fix capability struct values.
33 **/
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <math.h>
41 #include <inttypes.h>
42 #include <fcntl.h>
43 #include <sys/ioctl.h>
44 #include <linux/types.h>
45 #include <linux/version.h>
46 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
47 #include <linux/videodev2.h>
48 #endif
49 #include <linux/ivtv.h>
50 #include <linux/fb.h>
52 #include "vidix.h"
53 #include "vidixlib.h"
54 #include "fourcc.h"
55 #include "dha.h"
56 #include "pci_ids.h"
57 #include "pci_names.h"
59 #define VIDIX_STATIC ivtv_
61 #define IVTV_MSG "[ivtv-vid] "
62 #define MAXLINE 128
63 #define IVTVMAXWIDTH 720
64 #define IVTVMAXHEIGHT 576
66 static int fbdev = -1;
67 static int yuvdev = -1;
68 static void *memBase = NULL;
69 static int frameSize = 0;
70 static int probed = 0;
71 static int ivtv_verbose;
72 static vidix_rect_t destVideo;
73 static vidix_rect_t srcVideo;
74 static unsigned char *outbuf = NULL;
75 double fb_width;
76 double fb_height;
77 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
78 static struct ivtvfb_ioctl_state_info fb_state_old;
79 static struct ivtvfb_ioctl_state_info fb_state_hide;
80 #else
81 struct v4l2_format format_old, format_hide;
82 #endif
83 int alpha_disable = 0;
85 /* VIDIX exports */
87 static vidix_capability_t ivtv_cap =
89 "Hauppauge PVR 350 YUV Video",
90 "Lutz Koschorreck",
91 TYPE_OUTPUT,
92 { 0, 0, 0, 0 },
93 IVTVMAXWIDTH,
94 IVTVMAXHEIGHT,
97 -1,
98 FLAG_UPSCALER|FLAG_DOWNSCALER,
99 -1,
101 { 0, 0, 0, 0 }
104 static void de_macro_y(unsigned char *src, unsigned char *dst,
105 unsigned int w, unsigned int h, int src_x, int src_y, int height __attribute__ ((unused)), int width)
107 unsigned int x, y, i;
108 unsigned char *dst_2;
109 unsigned int h_tail, w_tail;
110 unsigned int h_size, w_size;
112 // Always round the origin, but compensate by increasing the size
113 if (src_x & 15) {
114 w += src_x & 15;
115 src_x &= ~15;
118 if (src_y & 15) {
119 h += src_y & 15;
120 src_y &= ~15;
123 // The right / bottom edge might not be a multiple of 16
124 h_tail = h & 15;
125 w_tail = w & 15;
127 // One block is 16 pixels high
128 h_size = 16;
130 // descramble Y plane
131 for (y = 0; y < h; y += 16) {
133 // Clip if we've reached the bottom & the size isn't a multiple of 16
134 if (y + 16 > h) h_size = h_tail;
136 for (x = 0; x < w; x += 16) {
137 if (x + 16 > w)
138 w_size = w_tail;
139 else
140 w_size = 16;
142 dst_2 = dst + (720 * y) + (720 * src_y) + (256 * (src_x>>4)) + (x * 16);
144 for (i = 0; i < h_size; i++) {
145 memcpy(dst_2, src + src_x + x + (y + i) * width + (src_y * width), w_size);
146 dst_2 += 16;
152 static void de_macro_uv(unsigned char *srcu, unsigned char *srcv,
153 unsigned char *dst, unsigned int w, unsigned int h, int src_x, int src_y,
154 int height, int width)
156 unsigned int x, y, i, f;
157 unsigned char *dst_2;
158 unsigned int h_tail, w_tail;
159 unsigned int h_size;
161 // The uv plane is half the size of the y plane, so 'correct' all dimensions.
162 w /= 2;
163 h /= 2;
164 src_x /= 2;
165 src_y /= 2;
166 height /= 2;
167 width /= 2;
169 // Always round the origin, but compensate by increasing the size
170 if (src_x & 7) {
171 w += src_x & 7;
172 src_x &= ~7;
175 if (src_y & 15) {
176 h += src_y & 15;
177 src_y &= ~15;
180 // The right / bottom edge may not be a multiple of 16
181 h_tail = h & 15;
182 w_tail = w & 7;
184 h_size = 16;
186 // descramble U/V plane
187 for (y = 0; y < h; y += 16) {
188 if ( y + 16 > h ) h_size = h_tail;
189 for (x = 0; x < w; x += 8) {
190 dst_2 = dst + (720 * y) + (720 * src_y) + (256 * (src_x>>3)) + (x * 32);
191 if (x + 8 <= w) {
192 for (i = 0; i < h_size; i++) {
193 int idx = src_x + x + ((y + i) * width) + (src_y * width);
194 dst_2[0] = srcu[idx + 0];
195 dst_2[1] = srcv[idx + 0];
196 dst_2[2] = srcu[idx + 1];
197 dst_2[3] = srcv[idx + 1];
198 dst_2[4] = srcu[idx + 2];
199 dst_2[5] = srcv[idx + 2];
200 dst_2[6] = srcu[idx + 3];
201 dst_2[7] = srcv[idx + 3];
202 dst_2[8] = srcu[idx + 4];
203 dst_2[9] = srcv[idx + 4];
204 dst_2[10] = srcu[idx + 5];
205 dst_2[11] = srcv[idx + 5];
206 dst_2[12] = srcu[idx + 6];
207 dst_2[13] = srcv[idx + 6];
208 dst_2[14] = srcu[idx + 7];
209 dst_2[15] = srcv[idx + 7];
210 dst_2 += 16;
213 else {
214 for (i = 0; i < h_size; i ++) {
215 int idx = src_x + x + ((y + i) * width) + (src_y * width);
216 for (f = 0; f < w_tail; f++) {
217 dst_2[0] = srcu[idx + f];
218 dst_2[1] = srcv[idx + f];
219 dst_2 += 2;
222 // Used for testing edge cutoff. Sets colour to Green
223 for (f = w_tail;f < 8;f ++) {
224 dst_2[0] = 0;
225 dst_2[1] = 0;
226 dst_2 += 2;
229 dst_2 += 16 - (w_tail << 1);
236 int ivtv_probe(int verbose,int force __attribute__ ((unused)))
238 unsigned char fb_number = 0;
239 char *device_name = NULL;
240 char *alpha = NULL;
241 struct fb_var_screeninfo vinfo;
242 char fb_dev_name[] = "/dev/fb0\0";
243 pciinfo_t lst[MAX_PCI_DEVICES];
244 int err = 0;
245 unsigned int i, num_pci = 0;
247 if(verbose)
248 printf(IVTV_MSG"probe\n");
250 ivtv_verbose = verbose;
252 err = pci_scan(lst, &num_pci);
253 if(err) {
254 printf(IVTV_MSG"Error occured during pci scan: %s\n", strerror(err));
255 return err;
258 if(ivtv_verbose)
259 printf(IVTV_MSG"Found %d pci devices\n", num_pci);
261 for(i = 0; i < num_pci; i++) {
262 if(2 == ivtv_verbose)
263 printf(IVTV_MSG"Found chip [%04X:%04X] '%s' '%s'\n"
264 ,lst[i].vendor
265 ,lst[i].device
266 ,pci_vendor_name(lst[i].vendor)
267 ,pci_device_name(lst[i].vendor,lst[i].device));
268 if(VENDOR_INTERNEXT == lst[i].vendor) {
269 switch(lst[i].device)
271 case DEVICE_INTERNEXT_ITVC15_MPEG_2_ENCODER:
272 if(ivtv_verbose)
273 printf(IVTV_MSG"Found PVR 350\n");
274 goto card_found;
279 if(ivtv_verbose)
280 printf(IVTV_MSG"Can't find chip\n");
281 return(ENXIO);
283 card_found:
285 device_name = getenv("FRAMEBUFFER");
286 if(NULL == device_name) {
287 device_name = fb_dev_name;
290 fb_number = atoi(device_name+strlen("/dev/fb"));
292 fbdev = open(device_name, O_RDWR);
293 if(-1 != fbdev) {
294 if(ioctl(fbdev, FBIOGET_VSCREENINFO, &vinfo) < 0) {
295 printf(IVTV_MSG"Unable to read screen info\n");
296 close(fbdev);
297 return(ENXIO);
298 } else {
299 fb_width = vinfo.xres;
300 fb_height = vinfo.yres;
301 if(2 == ivtv_verbose) {
302 printf(IVTV_MSG"framebuffer width : %3.0f\n",fb_width);
303 printf(IVTV_MSG"framebuffer height: %3.0f\n",fb_height);
306 if(NULL != (alpha = getenv("VIDIXIVTVALPHA"))) {
307 if(0 == strcmp(alpha, "disable")) {
308 alpha_disable = 1;
311 } else {
312 printf(IVTV_MSG"Failed to open /dev/fb%u\n", fb_number);
313 return(ENXIO);
316 /* Try to find YUV device */
317 unsigned char yuv_device_number = 48, yuv_device = 48 + fb_number;
318 char yuv_device_name[] = "/dev/videoXXX\0";
320 do {
321 sprintf(yuv_device_name, "/dev/video%u", yuv_device);
322 yuvdev = open(yuv_device_name, O_RDWR);
323 if(-1 != yuvdev) {
324 if(ivtv_verbose)
325 printf(IVTV_MSG"YUV device found /dev/video%u\n", yuv_device);
326 goto yuv_found;
327 } else {
328 if(ivtv_verbose)
329 printf(IVTV_MSG"YUV device not found: /dev/video%u\n", yuv_device);
331 } while(yuv_device-- > yuv_device_number);
332 return(ENXIO);
334 yuv_found:
335 if(0 == alpha_disable) {
336 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
337 if(ioctl(fbdev, IVTVFB_IOCTL_GET_STATE, &fb_state_old) < 0) {
338 printf(IVTV_MSG"Unable to read fb state\n");
339 close(yuvdev);
340 close(fbdev);
341 return(ENXIO);
342 } else {
343 if(ivtv_verbose) {
344 printf(IVTV_MSG"old alpha : %ld\n",fb_state_old.alpha);
345 printf(IVTV_MSG"old status: 0x%lx\n",fb_state_old.status);
347 fb_state_hide.alpha = 0;
348 fb_state_hide.status = fb_state_old.status | IVTVFB_STATUS_GLOBAL_ALPHA;
350 #else
351 memset(&format_old, 0, sizeof(format_old));
352 format_old.type = format_hide.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
353 if(ioctl(yuvdev, VIDIOC_G_FMT , &format_old) < 0) {
354 printf(IVTV_MSG"Unable to read fb state\n");
355 close(yuvdev);
356 close(fbdev);
357 return(ENXIO);
358 } else {
359 if(ivtv_verbose) {
360 printf(IVTV_MSG"old alpha : %d\n",format_old.fmt.win.global_alpha);
362 memcpy(&format_hide, &format_old, sizeof(format_old));
363 format_hide.fmt.win.global_alpha = 0;
365 #endif
367 probed = 1;
368 return(0);
371 int ivtv_init(const char *args __attribute__ ((unused)))
373 if(ivtv_verbose)
374 printf(IVTV_MSG"init\n");
376 if (!probed) {
377 if(ivtv_verbose)
378 printf(IVTV_MSG"Driver was not probed but is being initialized\n");
379 return(EINTR);
381 outbuf = malloc((IVTVMAXHEIGHT * IVTVMAXWIDTH) + (IVTVMAXHEIGHT * IVTVMAXWIDTH / 2));
382 if(NULL == outbuf) {
383 if(ivtv_verbose)
384 printf(IVTV_MSG"Not enough memory availabe!\n");
385 return(EINTR);
387 return(0);
390 void ivtv_destroy(void)
392 if(ivtv_verbose)
393 printf(IVTV_MSG"destroy\n");
394 if(-1 != yuvdev)
395 close(yuvdev);
396 if(-1 != fbdev)
397 close(fbdev);
398 if(NULL != outbuf)
399 free(outbuf);
400 if(NULL != memBase)
401 free(memBase);
404 int ivtv_get_caps(vidix_capability_t *to)
406 if(ivtv_verbose)
407 printf(IVTV_MSG"GetCap\n");
408 memcpy(to, &ivtv_cap, sizeof(vidix_capability_t));
409 return(0);
412 int ivtv_query_fourcc(vidix_fourcc_t *to)
414 if(ivtv_verbose)
415 printf(IVTV_MSG"query fourcc (%x)\n", to->fourcc);
417 int supports = 0;
418 switch(to->fourcc)
420 case IMGFMT_YV12:
421 supports = 1;
422 break;
423 default:
424 supports = 0;
427 if(!supports) {
428 to->depth = to->flags = 0;
429 return(ENOTSUP);
431 to->depth = VID_DEPTH_12BPP |
432 VID_DEPTH_15BPP | VID_DEPTH_16BPP |
433 VID_DEPTH_24BPP | VID_DEPTH_32BPP;
434 to->flags = 0;
435 return(0);
438 int ivtv_config_playback(vidix_playback_t *info)
440 if(ivtv_verbose)
441 printf(IVTV_MSG"config playback\n");
443 if(2 == ivtv_verbose){
444 printf(IVTV_MSG"src : x:%d y:%d w:%d h:%d\n",
445 info->src.x, info->src.y, info->src.w, info->src.h);
446 printf(IVTV_MSG"dest: x:%d y:%d w:%d h:%d\n",
447 info->dest.x, info->dest.y, info->dest.w, info->dest.h);
450 memcpy(&destVideo, &info->dest, sizeof(vidix_rect_t));
451 memcpy(&srcVideo, &info->src, sizeof(vidix_rect_t));
453 info->num_frames = 2;
454 info->frame_size = frameSize = info->src.w*info->src.h+(info->src.w*info->src.h)/2;
455 info->dest.pitch.y = 1;
456 info->dest.pitch.u = info->dest.pitch.v = 2;
457 info->offsets[0] = 0;
458 info->offsets[1] = info->frame_size;
459 info->offset.y = 0;
460 info->offset.u = info->src.w * info->src.h;
461 info->offset.v = info->offset.u + ((info->src.w * info->src.h)/4);
462 info->dga_addr = memBase = malloc(info->num_frames*info->frame_size);
463 if(ivtv_verbose)
464 printf(IVTV_MSG"frame_size: %d, dga_addr: %p\n",
465 info->frame_size, info->dga_addr);
466 return(0);
469 int ivtv_playback_on(void)
471 if(ivtv_verbose)
472 printf(IVTV_MSG"playback on\n");
474 if(0 == alpha_disable) {
475 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
476 if (-1 != fbdev) {
477 if (ioctl(fbdev, IVTVFB_IOCTL_SET_STATE, &fb_state_hide) < 0)
478 printf (IVTV_MSG"Failed to set fb state\n");
480 #else
481 if (-1 != yuvdev) {
482 if (ioctl(yuvdev, VIDIOC_S_FMT, &format_hide) < 0)
483 printf (IVTV_MSG"Failed to set fb state\n");
485 #endif
487 return(0);
490 int ivtv_playback_off(void)
492 if(ivtv_verbose)
493 printf(IVTV_MSG"playback off\n");
495 if(0 == alpha_disable) {
496 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
497 if (-1 != fbdev) {
498 if (ioctl(fbdev, IVTVFB_IOCTL_SET_STATE, &fb_state_old) < 0)
499 printf (IVTV_MSG"Failed to restore fb state\n");
501 #else
502 if (-1 != yuvdev) {
503 if (ioctl(yuvdev, VIDIOC_S_FMT, &format_old) < 0)
504 printf (IVTV_MSG"Failed to restore fb state\n");
506 #endif
508 return(0);
511 int ivtv_frame_sel(unsigned int frame)
514 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
515 struct ivtvyuv_ioctl_dma_host_to_ivtv_args args;
516 #else
517 struct ivtv_dma_frame args;
518 #endif
519 unsigned char *curMemBase = (unsigned char *)memBase + (frame * frameSize);
521 de_macro_y(curMemBase, outbuf, srcVideo.w, srcVideo.h, srcVideo.x, srcVideo.y, srcVideo.h, srcVideo.w);
522 de_macro_uv(curMemBase + (srcVideo.w * srcVideo.h) + srcVideo.w * srcVideo.h / 4,
523 curMemBase + (srcVideo.w * srcVideo.h), outbuf + (IVTVMAXHEIGHT * IVTVMAXWIDTH),
524 srcVideo.w, srcVideo.h, srcVideo.x, srcVideo.y, srcVideo.h, srcVideo.w);
526 args.y_source = outbuf;
527 args.uv_source = outbuf + (IVTVMAXHEIGHT * IVTVMAXWIDTH);
529 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
530 args.src_x = srcVideo.x;
531 args.src_y = srcVideo.y;
532 args.dst_x = destVideo.x;
533 args.dst_y = destVideo.y;
534 args.src_w = srcVideo.w;
535 args.dst_w = destVideo.w;
536 args.srcBuf_width = srcVideo.w;
537 args.src_h = srcVideo.h;
538 args.dst_h = destVideo.h;
539 args.srcBuf_height = srcVideo.h;
540 args.yuv_type = 0;
541 #else
542 args.src.left = srcVideo.x;
543 args.src.top = srcVideo.y;
544 args.dst.left = destVideo.x;
545 args.dst.top = destVideo.y;
546 args.src.width = srcVideo.w;
547 args.dst.width = destVideo.w;
548 args.src_width = srcVideo.w;
549 args.src.height = srcVideo.h;
550 args.dst.height = destVideo.h;
551 args.src_height = srcVideo.h;
552 args.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
553 #endif
555 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
556 if(ioctl(yuvdev, IVTV_IOC_PREP_FRAME_YUV, &args) == -1) {
557 #else
558 if(ioctl(yuvdev, IVTV_IOC_DMA_FRAME, &args) == -1) {
559 #endif
560 printf("Ioctl IVTV_IOC_DMA_FRAME returned failed Error\n");
562 return(0);
565 VDXDriver ivtv_drv = {
566 "ivtv",
567 NULL,
568 .probe = ivtv_probe,
569 .get_caps = ivtv_get_caps,
570 .query_fourcc = ivtv_query_fourcc,
571 .init = ivtv_init,
572 .destroy = ivtv_destroy,
573 .config_playback = ivtv_config_playback,
574 .playback_on = ivtv_playback_on,
575 .playback_off = ivtv_playback_off,
576 .frame_sel = ivtv_frame_sel,