PVR250 MCE with cxm driver under 6.0

Dylan Reid dgreid at gmail.com
Sun Nov 20 07:16:02 GMT 2005


I have MythTV 0.18 running on FreeBSD 6.0(amd64). I had to merge some
additional changes to the ones below to integrate the v4l2 support into the
cxm driver to get myth to work. I also had to make a few minor changes to
get myth to build properly.

Dylan

additional cxm patch:
diff -u ../dev/cxm/cxm.c ./cxm.c
--- ../dev/cxm/cxm.c Sun Nov 20 06:35:12 2005
+++ ./cxm.c Sun Nov 20 06:00:32 2005
@@ -80,6 +80,7 @@
#endif

#include <dev/cxm/cxm.h>
+#include <dev/cxm/cxm_v4l.h>

#include <dev/iicbus/iiconf.h>

@@ -333,7 +334,6 @@
48000
};

-
static const struct cxm_codec_profile
*codec_profiles[] = {
&vcd_ntsc_profile,
@@ -848,7 +848,7 @@
fps = cxm_saa7115_detected_fps(sc);

if (fps < 0)
- return -1;
+ /* return -1; */ fps = 30;

if (sc->profile->fps != fps) {

@@ -1762,8 +1762,10 @@
*/
if (cxm_ir_init(sc) < 0) {
device_printf(dev, "could not initialize IR remote\n");
+#ifndef PVR250_MCE
error = ENXIO;
goto fail;
+#endif
}

sc->dec_mbx = -1;
@@ -2192,8 +2194,9 @@
return ENXIO;
}

- if (sc->is_opened)
- return EBUSY;
+ if (sc->is_opened)
+ /* allow it to be open'ed more than once. */
+ return /* EBUSY */ 0;

sc->is_opened = 1;
sc->mpeg = 1;
@@ -2334,6 +2337,81 @@
return 0;
}

+#define NUM_INPUTS 10
+struct v4l2_input tmk_inputs[NUM_INPUTS] = {
+ {
+ .index = 0,
+ .name = "Composite 0",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 1,
+ .name = "Composite 1",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 2,
+ .name = "Composite 2",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 3,
+ .name = "Composite 3",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 4,
+ .name = "Tuner 0",
+ .type = V4L2_INPUT_TYPE_TUNER,
+ .audioset = 0,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 5,
+ .name = "Composite 4",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 6,
+ .name = "S-Video 0",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 7,
+ .name = "S-Video 1",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 8,
+ .name = "S-Video 2",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ },{
+ .index = 9,
+ .name = "S-Video 3",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 1,
+ .tuner = 0,
+ .status = 0,
+ }
+};
+

/*
*
@@ -2369,6 +2447,391 @@
}

switch (cmd) {
+
+ /* Video 4 Linux like ioctl's... */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *vcap = (struct v4l2_capability *)arg;
+ memset (vcap, 0, sizeof (*vcap));
+
+ /* driver name */
+ strcpy(vcap->driver,"CXM");
+
+ /* card type */
+ strcpy(vcap->card,"Hauppauge PVR-250");
+
+ /* bus info... */
+ strcpy(vcap->bus_info, "PCI:0");
+
+ /* version */
+ vcap->version = 0;
+
+ /* capabilities */
+ vcap->capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER|
+ V4L2_CAP_AUDIO|V4L2_CAP_READWRITE);
+
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *vfmt = (struct v4l2_format *)arg;
+ memset (vfmt, 0, sizeof (*vfmt));
+
+ vfmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vfmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ vfmt->fmt.pix.sizeimage = (128*1024);
+ vfmt->fmt.pix.width = sc->profile->width;
+ vfmt->fmt.pix.height = sc->profile->height;
+
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *vfmt = (struct v4l2_format *)arg;
+
+ if (sc->encoding)
+ return EBUSY;
+
+ if ((vfmt->fmt.pix.width % CXM_MACROBLOCK_WIDTH)
+ || (vfmt->fmt.pix.height % CXM_MACROBLOCK_HEIGHT))
+ return EINVAL;
+
+ /*
+ * Setting the width and height has the side effect of
+ * chosing between the VCD, SVCD, and DVD profiles.
+ */
+
+ for (i = 0; i < NUM_ELEMENTS(codec_profiles); i++)
+ if (codec_profiles[i]->width == vfmt->fmt.pix.width
+ && codec_profiles[i]->height == vfmt->fmt.pix.height)
+ break;
+
+ if (i >= NUM_ELEMENTS(codec_profiles))
+ {
+ /* need more codec profiles... just ignore for now */
+ break;
+ /* return EINVAL; */
+ } else {
+ sc->profile = codec_profiles[i];
+ }
+ break;
+ }
+ case VIDIOC_S_STD:
+ /* should try to set this to something else than NTSC */
+ break;
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *vin = (struct v4l2_input *)arg;
+
+ if ((vin->index < 0) || (vin->index >= NUM_INPUTS))
+ return(-EINVAL);
+
+ memcpy(vin, &tmk_inputs[vin->index], sizeof(struct v4l2_input));
+ vin->std = V4L2_STD_NTSC;
+ vin->status = 0;
+
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *vctrl = (struct v4l2_control *)arg;
+
+ switch (vctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ {
+
+ if (vctrl->value < 0 || vctrl->value > 255) {
+ return(-EINVAL);
+ }
+
+ if (cxm_saa7115_set_brightness(sc, vctrl->value) < 0)
+ return ENXIO;
+
+ break;
+ }
+ case V4L2_CID_HUE:
+ {
+ if (vctrl->value < -128 || vctrl->value > 127) {
+ return(-EINVAL);
+ }
+
+ if (cxm_saa7115_set_hue(sc, vctrl->value) < 0)
+ return ENXIO;
+
+ break;
+ }
+ case V4L2_CID_SATURATION:
+ {
+ if (vctrl->value < 0 || vctrl->value > 127) {
+ return(-EINVAL);
+ }
+
+ if (cxm_saa7115_set_chroma_saturation(sc,
+ vctrl->value) < 0)
+ return ENXIO;
+
+ break;
+ }
+ case V4L2_CID_CONTRAST:
+ {
+ if (vctrl->value < 0 || vctrl->value > 127) {
+ return(-EINVAL);
+ }
+
+ if (cxm_saa7115_set_contrast(sc, vctrl->value) < 0)
+ return ENXIO;
+
+ break;
+ }
+ case V4L2_CID_AUDIO_VOLUME:
+ {
+ if (vctrl->value > 65535 || vctrl->value < 0) {
+ return(-EINVAL);
+ }
+
+ break;
+ }
+ case V4L2_CID_AUDIO_MUTE:
+ {
+ if (vctrl->value) {
+ if (cxm_msp_mute(sc) < 0) return ENXIO;
+ } else {
+ if (cxm_msp_unmute(sc) < 0) return ENXIO;
+ }
+
+ break;
+ }
+ default:
+ return(-EINVAL);
+ }
+
+
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qctrl = (struct v4l2_queryctrl *)arg;
+
+ qctrl->flags = V4L2_CTRL_FLAG_DISABLED;
+
+ switch (qctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ {
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(qctrl->name, "Brightness", 32);
+ qctrl->minimum = 0;
+ qctrl->maximum = 255;
+ qctrl->step = 0;
+ qctrl->default_value = 128;
+ qctrl->flags = 0;
+ qctrl->reserved[0] = 0;
+ qctrl->reserved[1] = 0;
+ break;
+ }
+ case V4L2_CID_HUE:
+ {
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(qctrl->name, "Hue", 32);
+ qctrl->minimum = -128;
+ qctrl->maximum = 127;
+ qctrl->step = 0;
+ qctrl->default_value = 0;
+ qctrl->flags = 0;
+ qctrl->reserved[0] = 0;
+ qctrl->reserved[1] = 0;
+ break;
+ }
+ case V4L2_CID_SATURATION:
+ {
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(qctrl->name, "Saturation", 32);
+ qctrl->minimum = 0;
+ qctrl->maximum = 127;
+ qctrl->step = 0;
+ qctrl->default_value = 64;
+ qctrl->flags = 0;
+ qctrl->reserved[0] = 0;
+ qctrl->reserved[1] = 0;
+ break;
+ }
+ case V4L2_CID_CONTRAST:
+ {
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(qctrl->name, "Contrast", 32);
+ qctrl->minimum = 0;
+ qctrl->maximum = 127;
+ qctrl->step = 0;
+ qctrl->default_value = 64;
+ qctrl->flags = 0;
+ qctrl->reserved[0] = 0;
+ qctrl->reserved[1] = 0;
+ break;
+ }
+ case V4L2_CID_AUDIO_VOLUME:
+ {
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(qctrl->name, "Volume", 32);
+ qctrl->minimum = 0;
+ qctrl->maximum = 65535;
+ qctrl->step = 0;
+ qctrl->default_value = 65535;
+ qctrl->flags = 0;
+ qctrl->reserved[0] = 0;
+ qctrl->reserved[1] = 0;
+ break;
+ }
+ case V4L2_CID_AUDIO_MUTE:
+ {
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(qctrl->name, "Mute", 32);
+ qctrl->minimum = 0;
+ qctrl->maximum = 1;
+ qctrl->step = 0;
+ qctrl->default_value = 1;
+ qctrl->flags = 0;
+ qctrl->reserved[0] = 0;
+ qctrl->reserved[1] = 0;
+ break;
+ }
+ default:
+ {
+ if (qctrl->id < V4L2_CID_BASE ||
+ qctrl->id > V4L2_CID_LASTP1)
+ return EINVAL;
+ break;
+ }
+ } /* switch(qctrl->id) */
+
+ break;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int inp = *(int *)arg;
+
+ source = cxm_unknown_source;
+ printf("set input to %d\n", inp);
+ switch (inp) {
+ default:
+ case 4: // tuner on 250 mce
+ source = cxm_tuner_source;
+ break;
+
+ case 5: // composite on 250 mce
+ source = cxm_line_in_source_composite;
+ break;
+ }
+
+ if (sc->encoding) {
+
+ /*
+ * Switching between audio + video and audio only
+ * subtypes isn't supported while encoding.
+ */
+
+ if (source != sc->source
+ && (source == cxm_fm_source
+ || sc->source == cxm_fm_source))
+ return EBUSY;
+ }
+
+ if (cxm_pause_encoder(sc) < 0)
+ return ENXIO;
+
+ if (cxm_saa7115_select_source(sc, source) < 0)
+ return ENXIO;
+ if (cxm_msp_select_source(sc, source) < 0)
+ return ENXIO;
+
+ sc->source = source;
+
+ result = cxm_encoder_wait_for_lock(sc);
+ if (result < 0)
+ return ENXIO;
+ else if (result == 0)
+ return EINVAL;
+
+ if (cxm_unpause_encoder(sc) < 0)
+ return ENXIO;
+ break;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *vf=(struct v4l2_frequency *)arg;
+
+ /* Convert from Mhz * 16 to kHz */
+ unsigned long freq = (vf->frequency * 1000) / 16;
+ int result;
+
+ if (sc->source == cxm_tuner_source)
+ if (cxm_pause_encoder(sc) < 0)
+ return ENXIO;
+
+ if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
+ freq) < 0)
+ return ENXIO;
+
+ /*
+ * Explicitly wait for the tuner lock so we
+ * can indicate if there's a station present.
+ */
+ if (cxm_tuner_wait_for_lock(sc) < 0) {
+ sc->tuner_signal = 0;
+ /* return EINVAL; */
+ }
+
+ result = cxm_encoder_wait_for_lock(sc);
+ if (result < 0) {
+ return ENXIO;
+ } else if (result == 0) {
+ sc->tuner_signal = 0;
+ /* return EINVAL; */
+ } else {
+ sc->tuner_signal = 65535; /* best possible signal */
+ }
+
+ if (sc->source == cxm_tuner_source)
+ if (cxm_unpause_encoder(sc) < 0)
+ return ENXIO;
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+
+ vt->signal = sc->tuner_signal;
+ break;
+ }
+ case IVTV_IOC_G_CODEC:
+ {
+ struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg;
+ const struct cxm_codec_profile *cpp = sc->profile;
+
+ codec->aspect = cpp->aspect;
+ codec->audio_bitmask = cpp->audio_sample_rate;
+ codec->bframes = cpp->gop.bframes;
+ codec->bitrate_mode = cpp->bitrate.mode;
+ codec->bitrate = cpp->bitrate.average;
+ codec->bitrate_peak = cpp->bitrate.peak;
+ codec->dnr_spatial = cpp->dnr.spatial;
+ codec->dnr_temporal = cpp->dnr.temporal;
+ codec->dnr_type = cpp->dnr.type;
+ codec->framerate = cpp->fps == 30 ? 0 : 1;
+ codec->framespergop = cpp->gop.frames;
+ codec->gop_closure = cpp->gop.closure;
+ codec->pulldown = cpp->pulldown;
+ codec->stream_type = cpp->stream_type;
+
+ break;
+ }
+ case IVTV_IOC_S_CODEC:
+ {
+ /* struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg; */
+
+ /* FIXME - need to figure out how to set this stuff */
+ break;
+ }
+
+ /* Brooktree ioctl's ... */
case BT848_GAUDIO:
switch (cxm_msp_selected_source(sc)) {
case cxm_tuner_source:
@@ -2939,6 +3402,7 @@
break;

default:
+ printf("unknown ioctl\n");
return ENOTTY;
}

diff -u ../dev/cxm/cxm.h ./cxm.h
--- ../dev/cxm/cxm.h Sun Nov 20 06:35:12 2005
+++ ./cxm.h Mon Nov 14 06:35:35 2005
@@ -41,6 +41,8 @@

#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array))

+#define PVR250_MCE // define for media center edition
+
/*
* For simplicity several large buffers allocate during
* driver attachment which normally occurs early on
@@ -64,13 +66,13 @@
enum cxm_byte_order byte_order;
};

-#define CXM_SG_BUFFERS 50
+#define CXM_SG_BUFFERS 100

struct cxm_buffer_pool {
bus_dma_tag_t dmat;
size_t offset;
unsigned int read;
- volatile unsigned int write;
+ unsigned int write;
struct cxm_buffer bufs[CXM_SG_BUFFERS];
};

@@ -251,6 +253,7 @@
const struct cxm_tuner_channels *tuner_channels;
int tuner_afc;
unsigned long tuner_freq;
+ int tuner_signal;

char msp_name[10];

Only in .: cxm_dec_fw.c
Only in .: cxm_enc_fw.c
Only in .: cxm_extract_fw
Only in .: cxm_v4l.h
diff -u ../dev/cxm/cxm_video.c ./cxm_video.c
--- ../dev/cxm/cxm_video.c Sun Nov 20 06:35:12 2005
+++ ./cxm_video.c Mon Nov 14 06:09:33 2005
@@ -147,6 +147,21 @@
}
};

+#ifdef PVR250_MCE
+static struct cxm_saa7115_command
+saa7115_select_line_in_composite = {
+ 3,
+ {
+ /* Amp plus anti-alias filter, CVBS from AI24 */
+ { 0x02, 1, { 0xc5 } },
+ /* Adaptive luminance comb filter */
+ { 0x09, 1, { 0x40 } },
+
+ /* Enable AD2, audio clock, scaler, decoder */
+ { 0x88, 1, { 0xb0 } }
+ }
+};
+#else
static struct cxm_saa7115_command
saa7115_select_line_in_composite = {
3,
@@ -160,6 +175,7 @@
{ 0x88, 1, { 0x70 } }
}
};
+#endif

static struct cxm_saa7115_command
saa7115_select_line_in_svideo = {


Here are the MythTv 0.18 changes:
--- origmyth/mythtv-0.18.1/libs/libmythtv/videodev_myth.h Fri Jun 4 01:17:23
2004
+++ mythtv-0.18.1/libs/libmythtv/videodev_myth.h Wed Nov 16 06:20:14 2005
@@ -3,7 +3,7 @@

#ifdef __FreeBSD__
#include <sys/types.h>
-typedef unsigned long __u32;
+typedef unsigned int __u32;
typedef unsigned short __u16;
typedef int __s32;
typedef unsigned char __u8;

--- origmyth/mythtv-0.18.1/libs/libmyth/DisplayResX.cpp Thu Apr 7 15:33:49
2005
+++ mythtv-0.18.1/libs/libmyth/DisplayResX.cpp Thu Nov 17 01:33:22 2005
@@ -2,19 +2,19 @@
#include <cstring>
#include <cstdlib>

-namespace X11
-{
+//namespace X11
+//{
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
#include <X11/extensions/Xrandr.h>
-}
+//}

#include <iostream>

#include "DisplayResX.h"

-using namespace X11;
+//using namespace X11;

static XRRScreenConfiguration *GetScreenConfig(Display*& display);---
origmyth/mythtv-0.18.1/configure Thu May 5 07:15:43 2005
+++ mythtv-0.18.1/configure Sat Nov 19 04:04:39 2005
@@ -359,6 +359,6 @@
extralibs="$extralibs -lsocket -lnsl"
;;
FreeBSD)
-v4l="no"
+v4l="yes"
joystick_menu="no"
dv1394="no"
make="gmake"

On 11/9/05, Dylan Reid <dgreid at gmail.com> wrote:
>
> I have been trying to set up mythtv on FreeBSD 6.0 with an amd64 system.
> First thing was to get the capture card to work. I first applied patches for
> ports/85433 and ports/87518. This got me compiling. In order to get the
> module to load, I had to ignore the missing IR receiver.
>
> Next I wanted to use composite input, so I had to change which mode the
> saa7115 was configured to when the composite input was selected. I could not
> find a good way to determine dynamically if the card is an MCE or not. I did
> not look into this too hard however. So i just went with the easiest
> possible change. I did notice the Linux ivtv driver does not know the
> difference.
>
> Below are the patches I made in case anyone else wants to use the cxm
> driver with a 250 MCE.
>
> -Dylan
>
> --- cxm.c.orig Wed Nov 9 04:42:14 2005
> +++ cxm.c Wed Nov 9 04:51:56 2005
> @@ -1762,8 +1762,10 @@
> */
> if (cxm_ir_init(sc) < 0) {
> device_printf(dev, "could not initialize IR remote\n");
> +#ifndef PVR250_MCE
> error = ENXIO;
> goto fail;
> +#endif
> }
>
> sc->dec_mbx = -1;
> --- cxm.h.orig Wed Nov 9 04:59:32 2005
> +++ cxm.h Wed Nov 9 05:00:13 2005
> @@ -41,6 +41,8 @@
>
> #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array))
>
> +#define PVR250_MCE // define for media center edition
> +
> /*
> * For simplicity several large buffers allocate during
> * driver attachment which normally occurs early on
> --- cxm_video.c.orig Wed Nov 9 04:44:24 2005
> +++ cxm_video.c Wed Nov 9 05:21:44 2005
> @@ -147,6 +147,21 @@
> }
> };
>
> +#ifdef PVR250_MCE
> +static struct cxm_saa7115_command
> +saa7115_select_line_in_composite = {
> + 3,
> + {
> + /* Amp plus anti-alias filter, CVBS from AI24 */
> + { 0x02, 1, { 0xc5 } },
> + /* Adaptive luminance comb filter */
> + { 0x09, 1, { 0x40 } },
> +
> + /* Enable AD2, audio clock, scaler, decoder */
> + { 0x88, 1, { 0xb0 } }
> + }
> +};
> +#else
> static struct cxm_saa7115_command
> saa7115_select_line_in_composite = {
> 3,
> @@ -160,6 +175,7 @@
> { 0x88, 1, { 0x70 } }
> }
> };
> +#endif
>
> static struct cxm_saa7115_command
> saa7115_select_line_in_svideo = {
>
>


More information about the freebsd-multimedia mailing list