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.
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>
49 #include <linux/ivtv.h>
57 #include "pci_names.h"
59 #define VIDIX_STATIC ivtv_
61 #define IVTV_MSG "[ivtv-vid] "
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
;
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
;
81 struct v4l2_format format_old
, format_hide
;
83 int alpha_disable
= 0;
87 static vidix_capability_t ivtv_cap
=
89 "Hauppauge PVR 350 YUV Video",
98 FLAG_UPSCALER
|FLAG_DOWNSCALER
,
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
123 // The right / bottom edge might not be a multiple of 16
127 // One block is 16 pixels high
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) {
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
);
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
;
161 // The uv plane is half the size of the y plane, so 'correct' all dimensions.
169 // Always round the origin, but compensate by increasing the size
180 // The right / bottom edge may not be a multiple of 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);
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];
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
];
222 // Used for testing edge cutoff. Sets colour to Green
223 for (f = w_tail;f < 8;f ++) {
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
;
241 struct fb_var_screeninfo vinfo
;
242 char fb_dev_name
[] = "/dev/fb0\0";
243 pciinfo_t lst
[MAX_PCI_DEVICES
];
245 unsigned int i
, num_pci
= 0;
248 printf(IVTV_MSG
"probe\n");
250 ivtv_verbose
= verbose
;
252 err
= pci_scan(lst
, &num_pci
);
254 printf(IVTV_MSG
"Error occured during pci scan: %s\n", strerror(err
));
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"
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
:
273 printf(IVTV_MSG
"Found PVR 350\n");
280 printf(IVTV_MSG
"Can't find chip\n");
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
);
294 if(ioctl(fbdev
, FBIOGET_VSCREENINFO
, &vinfo
) < 0) {
295 printf(IVTV_MSG
"Unable to read screen info\n");
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")) {
312 printf(IVTV_MSG
"Failed to open /dev/fb%u\n", fb_number
);
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";
321 sprintf(yuv_device_name
, "/dev/video%u", yuv_device
);
322 yuvdev
= open(yuv_device_name
, O_RDWR
);
325 printf(IVTV_MSG
"YUV device found /dev/video%u\n", yuv_device
);
329 printf(IVTV_MSG
"YUV device not found: /dev/video%u\n", yuv_device
);
331 } while(yuv_device
-- > yuv_device_number
);
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");
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
;
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");
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;
371 int ivtv_init(const char *args
__attribute__ ((unused
)))
374 printf(IVTV_MSG
"init\n");
378 printf(IVTV_MSG
"Driver was not probed but is being initialized\n");
381 outbuf
= malloc((IVTVMAXHEIGHT
* IVTVMAXWIDTH
) + (IVTVMAXHEIGHT
* IVTVMAXWIDTH
/ 2));
384 printf(IVTV_MSG
"Not enough memory availabe!\n");
390 void ivtv_destroy(void)
393 printf(IVTV_MSG
"destroy\n");
404 int ivtv_get_caps(vidix_capability_t
*to
)
407 printf(IVTV_MSG
"GetCap\n");
408 memcpy(to
, &ivtv_cap
, sizeof(vidix_capability_t
));
412 int ivtv_query_fourcc(vidix_fourcc_t
*to
)
415 printf(IVTV_MSG
"query fourcc (%x)\n", to
->fourcc
);
428 to
->depth
= to
->flags
= 0;
431 to
->depth
= VID_DEPTH_12BPP
|
432 VID_DEPTH_15BPP
| VID_DEPTH_16BPP
|
433 VID_DEPTH_24BPP
| VID_DEPTH_32BPP
;
438 int ivtv_config_playback(vidix_playback_t
*info
)
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
;
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
);
464 printf(IVTV_MSG
"frame_size: %d, dga_addr: %p\n",
465 info
->frame_size
, info
->dga_addr
);
469 int ivtv_playback_on(void)
472 printf(IVTV_MSG
"playback on\n");
474 if(0 == alpha_disable
) {
475 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
477 if (ioctl(fbdev
, IVTVFB_IOCTL_SET_STATE
, &fb_state_hide
) < 0)
478 printf (IVTV_MSG
"Failed to set fb state\n");
482 if (ioctl(yuvdev
, VIDIOC_S_FMT
, &format_hide
) < 0)
483 printf (IVTV_MSG
"Failed to set fb state\n");
490 int ivtv_playback_off(void)
493 printf(IVTV_MSG
"playback off\n");
495 if(0 == alpha_disable
) {
496 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
498 if (ioctl(fbdev
, IVTVFB_IOCTL_SET_STATE
, &fb_state_old
) < 0)
499 printf (IVTV_MSG
"Failed to restore fb state\n");
503 if (ioctl(yuvdev
, VIDIOC_S_FMT
, &format_old
) < 0)
504 printf (IVTV_MSG
"Failed to restore fb state\n");
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
;
517 struct ivtv_dma_frame args
;
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
;
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
;
555 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
556 if(ioctl(yuvdev
, IVTV_IOC_PREP_FRAME_YUV
, &args
) == -1) {
558 if(ioctl(yuvdev
, IVTV_IOC_DMA_FRAME
, &args
) == -1) {
560 printf("Ioctl IVTV_IOC_DMA_FRAME returned failed Error\n");
565 VDXDriver ivtv_drv
= {
569 .get_caps
= ivtv_get_caps
,
570 .query_fourcc
= ivtv_query_fourcc
,
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
,