2 * VIDIX driver for Hauppauge PVR 350
4 * Copyright 2007 Lutz Koschorreck
5 * Based on genfb_vid.c and ivtv_xv.c
7 * This file is part of MPlayer.
9 * MPlayer is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * MPlayer is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include <sys/ioctl.h>
33 #include <linux/types.h>
34 #include <linux/version.h>
35 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
36 #include <linux/videodev2.h>
38 #include <linux/ivtv.h>
45 #include "pci_names.h"
47 #define VIDIX_STATIC ivtv_
49 #define IVTV_MSG "[ivtv-vid] "
51 #define IVTVMAXWIDTH 720
52 #define IVTVMAXHEIGHT 576
54 static int fbdev
= -1;
55 static int yuvdev
= -1;
56 static void *memBase
= NULL
;
57 static int frameSize
= 0;
58 static int probed
= 0;
59 static int ivtv_verbose
;
60 static vidix_rect_t destVideo
;
61 static vidix_rect_t srcVideo
;
62 static unsigned char *outbuf
= NULL
;
65 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
66 static struct ivtvfb_ioctl_state_info fb_state_old
;
67 static struct ivtvfb_ioctl_state_info fb_state_hide
;
69 struct v4l2_format format_old
, format_hide
;
71 int alpha_disable
= 0;
75 static vidix_capability_t ivtv_cap
=
77 "Hauppauge PVR 350 YUV Video",
86 FLAG_UPSCALER
|FLAG_DOWNSCALER
,
92 static void de_macro_y(unsigned char *src
, unsigned char *dst
,
93 unsigned int w
, unsigned int h
, int src_x
, int src_y
, int height
, int width
)
97 unsigned int h_tail
, w_tail
;
98 unsigned int h_size
, w_size
;
100 // Always round the origin, but compensate by increasing the size
111 // The right / bottom edge might not be a multiple of 16
115 // One block is 16 pixels high
118 // descramble Y plane
119 for (y
= 0; y
< h
; y
+= 16) {
121 // Clip if we've reached the bottom & the size isn't a multiple of 16
122 if (y
+ 16 > h
) h_size
= h_tail
;
124 for (x
= 0; x
< w
; x
+= 16) {
130 dst_2
= dst
+ (720 * y
) + (720 * src_y
) + (256 * (src_x
>>4)) + (x
* 16);
132 for (i
= 0; i
< h_size
; i
++) {
133 memcpy(dst_2
, src
+ src_x
+ x
+ (y
+ i
) * width
+ (src_y
* width
), w_size
);
140 static void de_macro_uv(unsigned char *srcu
, unsigned char *srcv
,
141 unsigned char *dst
, unsigned int w
, unsigned int h
, int src_x
, int src_y
,
142 int height
, int width
)
144 unsigned int x
, y
, i
, f
;
145 unsigned char *dst_2
;
146 unsigned int h_tail
, w_tail
;
149 // The uv plane is half the size of the y plane, so 'correct' all dimensions.
157 // Always round the origin, but compensate by increasing the size
168 // The right / bottom edge may not be a multiple of 16
174 // descramble U/V plane
175 for (y
= 0; y
< h
; y
+= 16) {
176 if ( y
+ 16 > h
) h_size
= h_tail
;
177 for (x
= 0; x
< w
; x
+= 8) {
178 dst_2
= dst
+ (720 * y
) + (720 * src_y
) + (256 * (src_x
>>3)) + (x
* 32);
180 for (i
= 0; i
< h_size
; i
++) {
181 int idx
= src_x
+ x
+ ((y
+ i
) * width
) + (src_y
* width
);
182 dst_2
[0] = srcu
[idx
+ 0];
183 dst_2
[1] = srcv
[idx
+ 0];
184 dst_2
[2] = srcu
[idx
+ 1];
185 dst_2
[3] = srcv
[idx
+ 1];
186 dst_2
[4] = srcu
[idx
+ 2];
187 dst_2
[5] = srcv
[idx
+ 2];
188 dst_2
[6] = srcu
[idx
+ 3];
189 dst_2
[7] = srcv
[idx
+ 3];
190 dst_2
[8] = srcu
[idx
+ 4];
191 dst_2
[9] = srcv
[idx
+ 4];
192 dst_2
[10] = srcu
[idx
+ 5];
193 dst_2
[11] = srcv
[idx
+ 5];
194 dst_2
[12] = srcu
[idx
+ 6];
195 dst_2
[13] = srcv
[idx
+ 6];
196 dst_2
[14] = srcu
[idx
+ 7];
197 dst_2
[15] = srcv
[idx
+ 7];
202 for (i
= 0; i
< h_size
; i
++) {
203 int idx
= src_x
+ x
+ ((y
+ i
) * width
) + (src_y
* width
);
204 for (f
= 0; f
< w_tail
; f
++) {
205 dst_2
[0] = srcu
[idx
+ f
];
206 dst_2
[1] = srcv
[idx
+ f
];
210 // Used for testing edge cutoff. Sets colour to Green
211 for (f = w_tail;f < 8;f ++) {
217 dst_2
+= 16 - (w_tail
<< 1);
224 int ivtv_probe(int verbose
, int force
)
226 unsigned char fb_number
= 0;
227 char *device_name
= NULL
;
229 struct fb_var_screeninfo vinfo
;
230 char fb_dev_name
[] = "/dev/fb0\0";
231 pciinfo_t lst
[MAX_PCI_DEVICES
];
233 unsigned int i
, num_pci
= 0;
234 unsigned char yuv_device_number
= 48, yuv_device
= 48 + fb_number
;
235 char yuv_device_name
[] = "/dev/videoXXX\0";
238 printf(IVTV_MSG
"probe\n");
240 ivtv_verbose
= verbose
;
242 err
= pci_scan(lst
, &num_pci
);
244 printf(IVTV_MSG
"Error occured during pci scan: %s\n", strerror(err
));
249 printf(IVTV_MSG
"Found %d pci devices\n", num_pci
);
251 for(i
= 0; i
< num_pci
; i
++) {
252 if(2 == ivtv_verbose
)
253 printf(IVTV_MSG
"Found chip [%04X:%04X] '%s' '%s'\n"
256 ,pci_vendor_name(lst
[i
].vendor
)
257 ,pci_device_name(lst
[i
].vendor
,lst
[i
].device
));
258 if(VENDOR_INTERNEXT
== lst
[i
].vendor
) {
259 switch(lst
[i
].device
)
261 case DEVICE_INTERNEXT_ITVC15_MPEG_2_ENCODER
:
263 printf(IVTV_MSG
"Found PVR 350\n");
270 printf(IVTV_MSG
"Can't find chip\n");
275 device_name
= getenv("FRAMEBUFFER");
276 if(NULL
== device_name
) {
277 device_name
= fb_dev_name
;
280 fb_number
= atoi(device_name
+strlen("/dev/fb"));
282 fbdev
= open(device_name
, O_RDWR
);
284 if(ioctl(fbdev
, FBIOGET_VSCREENINFO
, &vinfo
) < 0) {
285 printf(IVTV_MSG
"Unable to read screen info\n");
289 fb_width
= vinfo
.xres
;
290 fb_height
= vinfo
.yres
;
291 if(2 == ivtv_verbose
) {
292 printf(IVTV_MSG
"framebuffer width : %3.0f\n",fb_width
);
293 printf(IVTV_MSG
"framebuffer height: %3.0f\n",fb_height
);
296 if(NULL
!= (alpha
= getenv("VIDIXIVTVALPHA"))) {
297 if(0 == strcmp(alpha
, "disable")) {
302 printf(IVTV_MSG
"Failed to open /dev/fb%u\n", fb_number
);
306 /* Try to find YUV device */
308 sprintf(yuv_device_name
, "/dev/video%u", yuv_device
);
309 yuvdev
= open(yuv_device_name
, O_RDWR
);
312 printf(IVTV_MSG
"YUV device found /dev/video%u\n", yuv_device
);
316 printf(IVTV_MSG
"YUV device not found: /dev/video%u\n", yuv_device
);
318 } while(yuv_device
-- > yuv_device_number
);
322 if(0 == alpha_disable
) {
323 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
324 if(ioctl(fbdev
, IVTVFB_IOCTL_GET_STATE
, &fb_state_old
) < 0) {
325 printf(IVTV_MSG
"Unable to read fb state\n");
331 printf(IVTV_MSG
"old alpha : %ld\n",fb_state_old
.alpha
);
332 printf(IVTV_MSG
"old status: 0x%lx\n",fb_state_old
.status
);
334 fb_state_hide
.alpha
= 0;
335 fb_state_hide
.status
= fb_state_old
.status
| IVTVFB_STATUS_GLOBAL_ALPHA
;
338 memset(&format_old
, 0, sizeof(format_old
));
339 format_old
.type
= format_hide
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
;
340 if(ioctl(yuvdev
, VIDIOC_G_FMT
, &format_old
) < 0) {
341 printf(IVTV_MSG
"Unable to read fb state\n");
347 printf(IVTV_MSG
"old alpha : %d\n",format_old
.fmt
.win
.global_alpha
);
349 memcpy(&format_hide
, &format_old
, sizeof(format_old
));
350 format_hide
.fmt
.win
.global_alpha
= 0;
358 int ivtv_init(const char *args
)
361 printf(IVTV_MSG
"init\n");
365 printf(IVTV_MSG
"Driver was not probed but is being initialized\n");
368 outbuf
= malloc((IVTVMAXHEIGHT
* IVTVMAXWIDTH
) + (IVTVMAXHEIGHT
* IVTVMAXWIDTH
/ 2));
371 printf(IVTV_MSG
"Not enough memory availabe!\n");
377 void ivtv_destroy(void)
380 printf(IVTV_MSG
"destroy\n");
391 int ivtv_get_caps(vidix_capability_t
*to
)
394 printf(IVTV_MSG
"GetCap\n");
395 memcpy(to
, &ivtv_cap
, sizeof(vidix_capability_t
));
399 int ivtv_query_fourcc(vidix_fourcc_t
*to
)
404 printf(IVTV_MSG
"query fourcc (%x)\n", to
->fourcc
);
416 to
->depth
= to
->flags
= 0;
419 to
->depth
= VID_DEPTH_12BPP
|
420 VID_DEPTH_15BPP
| VID_DEPTH_16BPP
|
421 VID_DEPTH_24BPP
| VID_DEPTH_32BPP
;
426 int ivtv_config_playback(vidix_playback_t
*info
)
429 printf(IVTV_MSG
"config playback\n");
431 if(2 == ivtv_verbose
){
432 printf(IVTV_MSG
"src : x:%d y:%d w:%d h:%d\n",
433 info
->src
.x
, info
->src
.y
, info
->src
.w
, info
->src
.h
);
434 printf(IVTV_MSG
"dest: x:%d y:%d w:%d h:%d\n",
435 info
->dest
.x
, info
->dest
.y
, info
->dest
.w
, info
->dest
.h
);
438 memcpy(&destVideo
, &info
->dest
, sizeof(vidix_rect_t
));
439 memcpy(&srcVideo
, &info
->src
, sizeof(vidix_rect_t
));
441 info
->num_frames
= 2;
442 info
->frame_size
= frameSize
= info
->src
.w
*info
->src
.h
+(info
->src
.w
*info
->src
.h
)/2;
443 info
->dest
.pitch
.y
= 1;
444 info
->dest
.pitch
.u
= info
->dest
.pitch
.v
= 2;
445 info
->offsets
[0] = 0;
446 info
->offsets
[1] = info
->frame_size
;
448 info
->offset
.u
= info
->src
.w
* info
->src
.h
;
449 info
->offset
.v
= info
->offset
.u
+ ((info
->src
.w
* info
->src
.h
)/4);
450 info
->dga_addr
= memBase
= malloc(info
->num_frames
*info
->frame_size
);
452 printf(IVTV_MSG
"frame_size: %d, dga_addr: %p\n",
453 info
->frame_size
, info
->dga_addr
);
457 int ivtv_playback_on(void)
460 printf(IVTV_MSG
"playback on\n");
462 if(0 == alpha_disable
) {
463 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
465 if (ioctl(fbdev
, IVTVFB_IOCTL_SET_STATE
, &fb_state_hide
) < 0)
466 printf (IVTV_MSG
"Failed to set fb state\n");
470 if (ioctl(yuvdev
, VIDIOC_S_FMT
, &format_hide
) < 0)
471 printf (IVTV_MSG
"Failed to set fb state\n");
478 int ivtv_playback_off(void)
481 printf(IVTV_MSG
"playback off\n");
483 if(0 == alpha_disable
) {
484 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
486 if (ioctl(fbdev
, IVTVFB_IOCTL_SET_STATE
, &fb_state_old
) < 0)
487 printf (IVTV_MSG
"Failed to restore fb state\n");
491 if (ioctl(yuvdev
, VIDIOC_S_FMT
, &format_old
) < 0)
492 printf (IVTV_MSG
"Failed to restore fb state\n");
499 int ivtv_frame_sel(unsigned int frame
)
502 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
503 struct ivtvyuv_ioctl_dma_host_to_ivtv_args args
;
505 struct ivtv_dma_frame args
;
507 unsigned char *curMemBase
= (unsigned char *)memBase
+ (frame
* frameSize
);
509 de_macro_y(curMemBase
, outbuf
, srcVideo
.w
, srcVideo
.h
, srcVideo
.x
, srcVideo
.y
, srcVideo
.h
, srcVideo
.w
);
510 de_macro_uv(curMemBase
+ (srcVideo
.w
* srcVideo
.h
) + srcVideo
.w
* srcVideo
.h
/ 4,
511 curMemBase
+ (srcVideo
.w
* srcVideo
.h
), outbuf
+ (IVTVMAXHEIGHT
* IVTVMAXWIDTH
),
512 srcVideo
.w
, srcVideo
.h
, srcVideo
.x
, srcVideo
.y
, srcVideo
.h
, srcVideo
.w
);
514 args
.y_source
= outbuf
;
515 args
.uv_source
= outbuf
+ (IVTVMAXHEIGHT
* IVTVMAXWIDTH
);
517 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
518 args
.src_x
= srcVideo
.x
;
519 args
.src_y
= srcVideo
.y
;
520 args
.dst_x
= destVideo
.x
;
521 args
.dst_y
= destVideo
.y
;
522 args
.src_w
= srcVideo
.w
;
523 args
.dst_w
= destVideo
.w
;
524 args
.srcBuf_width
= srcVideo
.w
;
525 args
.src_h
= srcVideo
.h
;
526 args
.dst_h
= destVideo
.h
;
527 args
.srcBuf_height
= srcVideo
.h
;
530 args
.src
.left
= srcVideo
.x
;
531 args
.src
.top
= srcVideo
.y
;
532 args
.dst
.left
= destVideo
.x
;
533 args
.dst
.top
= destVideo
.y
;
534 args
.src
.width
= srcVideo
.w
;
535 args
.dst
.width
= destVideo
.w
;
536 args
.src_width
= srcVideo
.w
;
537 args
.src
.height
= srcVideo
.h
;
538 args
.dst
.height
= destVideo
.h
;
539 args
.src_height
= srcVideo
.h
;
540 args
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
543 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
544 if(ioctl(yuvdev
, IVTV_IOC_PREP_FRAME_YUV
, &args
) == -1) {
546 if(ioctl(yuvdev
, IVTV_IOC_DMA_FRAME
, &args
) == -1) {
548 printf("Ioctl IVTV_IOC_DMA_FRAME returned failed Error\n");
553 VDXDriver ivtv_drv
= {
557 .get_caps
= ivtv_get_caps
,
558 .query_fourcc
= ivtv_query_fourcc
,
560 .destroy
= ivtv_destroy
,
561 .config_playback
= ivtv_config_playback
,
562 .playback_on
= ivtv_playback_on
,
563 .playback_off
= ivtv_playback_off
,
564 .frame_sel
= ivtv_frame_sel
,