xf86-video-intel: 5 commits - src/i830_sdvo.c src/i830_sdvo_regs.h

Eric Anholt anholt at kemper.freedesktop.org
Wed Apr 2 16:20:03 PDT 2008


 src/i830_sdvo.c      |  329 +++++++++++++++++++++++++++++++++++++++++++++------
 src/i830_sdvo_regs.h |  194 +++++++++++++++++++++++++++++-
 2 files changed, 481 insertions(+), 42 deletions(-)

New commits:
commit 13563bd65cbbbb3e697dacd814efa3517e1493dc
Author: Hong Liu <hong.liu at intel.com>
Date:   Wed Apr 2 16:05:43 2008 -0700

    SDVO: Fix DDC bus selection based on output priority list.

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 46213a2..642ba88 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -92,6 +92,9 @@ struct i830_sdvo_priv {
      */
     struct i830_sdvo_tv_format tv_format;
 
+    /** DDC bus used by this SDVO output */
+    uint8_t ddc_bus;
+
     /** State for save/restore */
     /** @{ */
     int save_sdvo_mult;
@@ -1011,8 +1014,9 @@ i830_sdvo_ddc_i2c_start(I2CBusPtr b, int timeout)
     xf86OutputPtr	    output = b->DriverPrivate.ptr;
     I830OutputPrivatePtr    intel_output = output->driver_private;
     I2CBusPtr		    i2cbus = intel_output->pI2CBus;
+    struct i830_sdvo_priv   *dev_priv = intel_output->dev_priv;
 
-    i830_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2);
+    i830_sdvo_set_control_bus_switch(output, dev_priv->ddc_bus);
     return i2cbus->I2CStart(i2cbus, timeout);
 }
 
@@ -1342,6 +1346,60 @@ static const xf86OutputFuncsRec i830_sdvo_output_funcs = {
 #endif
 };
 
+static unsigned int count_bits(uint32_t mask)
+{
+    unsigned int n;
+
+    for (n = 0; mask; n++)
+	mask &= mask - 1;
+
+    return n;
+}
+
+/**
+ * Choose the appropriate DDC bus for control bus switch command for this
+ * SDVO output based on the controlled output.
+ *
+ * DDC bus number assignment is in a priority order of RGB outputs, then TMDS
+ * outputs, then LVDS outputs.
+ */
+static void
+i830_sdvo_select_ddc_bus(struct i830_sdvo_priv *dev_priv)
+{
+    uint16_t mask = 0;
+    unsigned int num_bits;
+
+    /* Make a mask of outputs less than or equal to our own priority in the
+     * list.
+     */
+    switch (dev_priv->controlled_output) {
+    case SDVO_OUTPUT_LVDS1:
+	mask |= SDVO_OUTPUT_LVDS1;
+    case SDVO_OUTPUT_LVDS0:
+	mask |= SDVO_OUTPUT_LVDS0;
+    case SDVO_OUTPUT_TMDS1:
+	mask |= SDVO_OUTPUT_TMDS1;
+    case SDVO_OUTPUT_TMDS0:
+	mask |= SDVO_OUTPUT_TMDS0;
+    case SDVO_OUTPUT_RGB1:
+	mask |= SDVO_OUTPUT_RGB1;
+    case SDVO_OUTPUT_RGB0:
+	mask |= SDVO_OUTPUT_RGB0;
+	break;
+    }
+
+    /* Count bits to find what number we are in the priority list. */
+    mask &= dev_priv->caps.output_flags;
+    num_bits = count_bits(mask);
+    if (num_bits > 3) {
+	/* if more than 3 outputs, default to DDC bus 3 for now */
+	num_bits = 3;
+    }
+
+    /* Corresponds to SDVO_CONTROL_BUS_DDCx */
+    dev_priv->ddc_bus = 1 << num_bits;
+}
+
 void
 i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 {
@@ -1510,8 +1568,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 	xf86OutputDestroy (output);
 	return;
     }
-	
-    
+
+    i830_sdvo_select_ddc_bus(dev_priv);
+
     /* Set the input timing to the screen. Assume always input 0. */
     i830_sdvo_set_target_input(output, TRUE, FALSE);
 
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index 3a2deaf..dc2522a 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -506,8 +506,8 @@ struct i830_sdvo_enhancements_arg {
 #define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93
 
 #define SDVO_CMD_SET_CONTROL_BUS_SWITCH			0x7a
-# define SDVO_CONTROL_BUS_PROM				0x0
-# define SDVO_CONTROL_BUS_DDC1				0x1
-# define SDVO_CONTROL_BUS_DDC2				0x2
-# define SDVO_CONTROL_BUS_DDC3				0x3
+# define SDVO_CONTROL_BUS_PROM				(1 << 0)
+# define SDVO_CONTROL_BUS_DDC1				(1 << 1)
+# define SDVO_CONTROL_BUS_DDC2				(1 << 2)
+# define SDVO_CONTROL_BUS_DDC3				(1 << 3)
 
commit 6ad2d6ba86689674876f5f4c473f11e39243ac38
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Apr 2 15:16:17 2008 -0700

    SDVO: Fix mixups with input and output channels.
    
    The 2-bit input_mask was actually an input count -- in0 is always there, and
    in1 is optional.
    
    The output flags weren't being reported in the log, so I mistakenly took
    controlled_output == RGB0 to mean that the device only reported an RGB0,
    while it actually reported RGB0|SVID0|YPRPB0|misc|other.  Move SVID0 up
    in priority and remove the RGB-is-it-really-TV hack I had just come up with.
    
    Finally, set the input/output mapping at mode set time.  We're always
    supposed to do this, but haven't had to so far as we've never handled
    devices with more than one output.

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 59d97c6..46213a2 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -230,7 +230,7 @@ const static struct _sdvo_cmd_name {
 
 static I2CSlaveAddr slaveAddr;
 
-#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVO" : "SDVO")
+#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
 #define SDVO_PRIV(output)   ((struct i830_sdvo_priv *) (output)->dev_priv)
 
 /**
@@ -668,13 +668,26 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
     uint16_t width, height;
     uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
     uint16_t h_sync_offset, v_sync_offset;
+    struct i830_sdvo_in_out_map in_out;
     struct i830_sdvo_dtd output_dtd;
-    uint16_t no_outputs;
-
-    no_outputs = 0;
+    uint8_t status;
 
     if (!mode)
 	return;
+
+    /* First, set the input mapping for the first input to our controlled
+     * output. This is only correct if we're a single-input device, in
+     * which case the first input is the output from the appropriate SDVO
+     * channel on the motherboard.  In a two-input device, the first input
+     * will be SDVOB and the second SDVOC.
+     */
+    in_out.in0 = dev_priv->controlled_output;
+    in_out.in1 = 0;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_SET_IN_OUT_MAP,
+			&in_out, sizeof(in_out));
+    status = i830_sdvo_read_response(output, NULL, 0);
+
     width = mode->CrtcHDisplay;
     height = mode->CrtcVDisplay;
     
@@ -843,12 +856,10 @@ i830_sdvo_save(xf86OutputPtr output)
     dev_priv->save_sdvo_mult = i830_sdvo_get_clock_rate_mult(output);
     i830_sdvo_get_active_outputs(output, &dev_priv->save_active_outputs);
 
-    if (dev_priv->caps.sdvo_inputs_mask & 0x1) {
-       i830_sdvo_set_target_input(output, TRUE, FALSE);
-       i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1);
-    }
+    i830_sdvo_set_target_input(output, TRUE, FALSE);
+    i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1);
 
-    if (dev_priv->caps.sdvo_inputs_mask & 0x2) {
+    if (dev_priv->caps.sdvo_input_count >= 2) {
        i830_sdvo_set_target_input(output, FALSE, TRUE);
        i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_2);
     }
@@ -892,12 +903,10 @@ i830_sdvo_restore(xf86OutputPtr output)
 	}
     }
 
-    if (dev_priv->caps.sdvo_inputs_mask & 0x1) {
-       i830_sdvo_set_target_input(output, TRUE, FALSE);
-       i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1);
-    }
+    i830_sdvo_set_target_input(output, TRUE, FALSE);
+    i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1);
 
-    if (dev_priv->caps.sdvo_inputs_mask & 0x2) {
+    if (dev_priv->caps.sdvo_input_count >= 2) {
        i830_sdvo_set_target_input(output, FALSE, TRUE);
        i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_2);
     }
@@ -1345,7 +1354,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     char		    name[60];
     char		    *name_prefix;
     char		    *name_suffix;
-    struct i830_sdvo_tv_format tv_formats;
 
     output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL);
     if (!output)
@@ -1463,6 +1471,13 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="TMDS";
     }
+    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
+        output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
+	name_prefix="TV";
+	dev_priv->is_tv = TRUE;
+    }
     else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
     {
 	dev_priv->controlled_output = SDVO_OUTPUT_RGB0;
@@ -1475,13 +1490,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="VGA";
     }
-    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
-    {
-	dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
-        output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
-	name_prefix="S-Video";
-	dev_priv->is_tv = TRUE;
-    }
     else
     {
 	unsigned char	bytes[2];
@@ -1495,21 +1503,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 	name_prefix="Unknown";
     }
 
-    if (dev_priv->controlled_output == SDVO_OUTPUT_RGB0 ||
-	dev_priv->controlled_output == SDVO_OUTPUT_RGB1) {
-	uint8_t status;
-
-	/* Detect if an RGB device is actually a TV device.  This is the
-	 * case for our HDMI+S-Video SDVO card.
-	 */
-	i830_sdvo_write_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
-			    NULL, 0);
-	status = i830_sdvo_read_response(output,
-					 &tv_formats, sizeof(tv_formats));
-	if (status == SDVO_CMD_STATUS_SUCCESS)
-	    dev_priv->is_tv = TRUE;
-    }
-
     strcpy (name, name_prefix);
     strcat (name, name_suffix);
     if (!xf86OutputRename (output, name))
@@ -1526,17 +1519,40 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 					  &dev_priv->pixel_clock_max);
 
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-	       "%s device VID/DID: %02X:%02X.%02X, "
-	       "clock range %.1fMHz - %.1fMHz, "
-	       "input 1: %c, input 2: %c, "
-	       "output 1: %c, output 2: %c\n",
+	       "%s: device VID/DID: %02X:%02X.%02X, "
+	       "clock range %.1fMHz - %.1fMHz\n",
 	       SDVO_NAME(dev_priv),
 	       dev_priv->caps.vendor_id, dev_priv->caps.device_id,
 	       dev_priv->caps.device_rev_id,
 	       dev_priv->pixel_clock_min / 1000.0,
-	       dev_priv->pixel_clock_max / 1000.0,
-	       (dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
-	       (dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
-	       dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_TMDS0) ? 'Y' : 'N',
-	       dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB1 | SDVO_OUTPUT_TMDS1) ? 'Y' : 'N');
+	       dev_priv->pixel_clock_max / 1000.0);
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	       "%s: %d input channel%s\n",
+	       SDVO_NAME(dev_priv), dev_priv->caps.sdvo_input_count,
+	       dev_priv->caps.sdvo_input_count >= 2 ? "s" : "");
+
+#define REPORT_OUTPUT_FLAG(flag, name) do {				\
+    if (dev_priv->caps.output_flags & flag) {				\
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s: %s output reported\n", \
+		   SDVO_NAME(dev_priv), name);				\
+    }									\
+} while (0)
+
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_TMDS0, "TMDS0");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_RGB0, "RGB0");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_CVBS0, "CVBS0");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SVID0, "SVID0");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_YPRPB0, "YPRPB0");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SCART0, "SCART0");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_LVDS0, "LVDS0");
+
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_TMDS1, "TMDS1");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_RGB1, "RGB1");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_CVBS1, "CVBS1");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SVID1, "SVID1");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_YPRPB1, "YPRPB1");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SCART1, "SCART1");
+    REPORT_OUTPUT_FLAG(SDVO_OUTPUT_LVDS1, "LVDS1");
+
 }
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index 63688ac..3a2deaf 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -52,7 +52,7 @@ struct i830_sdvo_caps {
     uint8_t device_rev_id;
     uint8_t sdvo_version_major;
     uint8_t sdvo_version_minor;
-    unsigned int sdvo_inputs_mask:2;
+    unsigned int sdvo_input_count:2;
     unsigned int smooth_scaling:1;
     unsigned int sharp_scaling:1;
     unsigned int up_scaling:1;
@@ -174,6 +174,9 @@ struct i830_sdvo_get_trained_inputs_response {
  * Returns two struct i830_sdvo_output_flags structures.
  */
 #define SDVO_CMD_GET_IN_OUT_MAP				0x06
+struct i830_sdvo_in_out_map {
+    uint16_t in0, in1;
+};
 
 /**
  * Sets the current mapping of SDVO inputs to outputs on the device.
commit 3a17400dc67534f0eb474ece080f01061469569c
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Apr 2 14:21:23 2008 -0700

    SDVO: Handle RGB outputs that are really TV outputs, and select a TV format.
    
    Still doesn't light anything up.

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 6c23c15..59d97c6 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -69,6 +69,29 @@ struct i830_sdvo_priv {
     /** Pixel clock limitations reported by the SDVO device, in kHz */
     int pixel_clock_min, pixel_clock_max;
 
+    /**
+     * This is set if we're going to treat the device as TV-out.
+     *
+     * While we have these nice friendly flags for output types that ought to
+     * decide this for us, the S-Video output on our HDMI+S-Video card shows
+     * up as RGB1 (VGA).
+     */
+    Bool is_tv;
+
+    /**
+     * Returned SDTV resolutions allowed for the current format, if the
+     * device reported it.
+     */
+    struct i830_sdvo_sdtv_resolution_reply sdtv_resolutions;
+
+    /**
+     * Current selected TV format.
+     *
+     * This is stored in the same structure that's passed to the device, for
+     * convenience.
+     */
+    struct i830_sdvo_tv_format tv_format;
+
     /** State for save/restore */
     /** @{ */
     int save_sdvo_mult;
@@ -201,6 +224,8 @@ const static struct _sdvo_cmd_name {
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),
 };
 
 static I2CSlaveAddr slaveAddr;
@@ -837,6 +862,9 @@ i830_sdvo_save(xf86OutputPtr output)
 	    i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd[o]);
 	}
     }
+    if (dev_priv->is_tv) {
+	/* XXX: Save TV format/enhancements. */
+    }
 
     dev_priv->save_SDVOX = INREG(dev_priv->output_device);
 }
@@ -876,6 +904,10 @@ i830_sdvo_restore(xf86OutputPtr output)
 
     i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult);
 
+    if (dev_priv->is_tv) {
+	/* XXX: Restore TV format/enhancements. */
+    }
+
     i830_sdvo_write_sdvox(output, dev_priv->save_SDVOX);
 
     if (dev_priv->save_SDVOX & SDVO_ENABLE)
@@ -1052,6 +1084,8 @@ i830_sdvo_dump_device(xf86OutputPtr output)
     i830_sdvo_dump_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT);
     i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS);
     i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TV_FORMAT);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT);
+    i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS);
 }
 
 void
@@ -1169,40 +1203,73 @@ i830_sdvo_get_tv_mode(DisplayModePtr *head, int width, int height,
 	*head = mode;
 }
 
+/**
+ * This function checks the current TV format, and chooses a default if
+ * it hasn't been set.
+ */
+static void
+i830_sdvo_check_tv_format(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+    struct i830_sdvo_tv_format format, unset;
+    uint8_t status;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
+    status = i830_sdvo_read_response(output, &format, sizeof(format));
+    if (status != SDVO_CMD_STATUS_SUCCESS)
+	return;
+
+    memset(&unset, 0, sizeof(unset));
+    if (memcmp(&format, &unset, sizeof(format))) {
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "%s: Choosing default TV format of NTSC-M\n",
+		   SDVO_NAME(dev_priv));
+
+	format.ntsc_m = TRUE;
+	i830_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
+	status = i830_sdvo_read_response(output, NULL, 0);
+    }
+}
+
 static DisplayModePtr
 i830_sdvo_get_tv_modes(xf86OutputPtr output)
 {
-    ScrnInfoPtr pScrn = output->scrn;
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
     DisplayModePtr modes = NULL;
-    struct i830_sdvo_sdtv_resolution_reply res;
+    struct i830_sdvo_sdtv_resolution_reply *res = &dev_priv->sdtv_resolutions;
     uint8_t status;
     float refresh = 60; /* XXX */
 
+    i830_sdvo_check_tv_format(output);
+
     /* Read the list of supported input resolutions for the selected TV format.
      */
     i830_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, NULL, 0);
-    status = i830_sdvo_read_response(output, &res, sizeof(res));
+    status = i830_sdvo_read_response(output, res, sizeof(*res));
     if (status != SDVO_CMD_STATUS_SUCCESS)
 	return NULL;
 
-    if (res.res_320x200) i830_sdvo_get_tv_mode(&modes, 320, 200, refresh);
-    if (res.res_320x240) i830_sdvo_get_tv_mode(&modes, 320, 240, refresh);
-    if (res.res_400x300) i830_sdvo_get_tv_mode(&modes, 400, 300, refresh);
-    if (res.res_640x350) i830_sdvo_get_tv_mode(&modes, 640, 350, refresh);
-    if (res.res_640x400) i830_sdvo_get_tv_mode(&modes, 640, 400, refresh);
-    if (res.res_640x480) i830_sdvo_get_tv_mode(&modes, 640, 480, refresh);
-    if (res.res_704x480) i830_sdvo_get_tv_mode(&modes, 704, 480, refresh);
-    if (res.res_704x576) i830_sdvo_get_tv_mode(&modes, 704, 576, refresh);
-    if (res.res_720x350) i830_sdvo_get_tv_mode(&modes, 720, 350, refresh);
-    if (res.res_720x400) i830_sdvo_get_tv_mode(&modes, 720, 400, refresh);
-    if (res.res_720x480) i830_sdvo_get_tv_mode(&modes, 720, 480, refresh);
-    if (res.res_720x540) i830_sdvo_get_tv_mode(&modes, 720, 540, refresh);
-    if (res.res_720x576) i830_sdvo_get_tv_mode(&modes, 720, 576, refresh);
-    if (res.res_800x600) i830_sdvo_get_tv_mode(&modes, 800, 600, refresh);
-    if (res.res_832x624) i830_sdvo_get_tv_mode(&modes, 832, 624, refresh);
-    if (res.res_920x766) i830_sdvo_get_tv_mode(&modes, 920, 766, refresh);
-    if (res.res_1024x768) i830_sdvo_get_tv_mode(&modes, 1024, 768, refresh);
-    if (res.res_1280x1024) i830_sdvo_get_tv_mode(&modes, 1280, 1024, refresh);
+    if (res->res_320x200) i830_sdvo_get_tv_mode(&modes, 320, 200, refresh);
+    if (res->res_320x240) i830_sdvo_get_tv_mode(&modes, 320, 240, refresh);
+    if (res->res_400x300) i830_sdvo_get_tv_mode(&modes, 400, 300, refresh);
+    if (res->res_640x350) i830_sdvo_get_tv_mode(&modes, 640, 350, refresh);
+    if (res->res_640x400) i830_sdvo_get_tv_mode(&modes, 640, 400, refresh);
+    if (res->res_640x480) i830_sdvo_get_tv_mode(&modes, 640, 480, refresh);
+    if (res->res_704x480) i830_sdvo_get_tv_mode(&modes, 704, 480, refresh);
+    if (res->res_704x576) i830_sdvo_get_tv_mode(&modes, 704, 576, refresh);
+    if (res->res_720x350) i830_sdvo_get_tv_mode(&modes, 720, 350, refresh);
+    if (res->res_720x400) i830_sdvo_get_tv_mode(&modes, 720, 400, refresh);
+    if (res->res_720x480) i830_sdvo_get_tv_mode(&modes, 720, 480, refresh);
+    if (res->res_720x540) i830_sdvo_get_tv_mode(&modes, 720, 540, refresh);
+    if (res->res_720x576) i830_sdvo_get_tv_mode(&modes, 720, 576, refresh);
+    if (res->res_800x600) i830_sdvo_get_tv_mode(&modes, 800, 600, refresh);
+    if (res->res_832x624) i830_sdvo_get_tv_mode(&modes, 832, 624, refresh);
+    if (res->res_920x766) i830_sdvo_get_tv_mode(&modes, 920, 766, refresh);
+    if (res->res_1024x768) i830_sdvo_get_tv_mode(&modes, 1024, 768, refresh);
+    if (res->res_1280x1024) i830_sdvo_get_tv_mode(&modes, 1280, 1024, refresh);
 
     return modes;
 }
@@ -1213,7 +1280,7 @@ i830_sdvo_get_modes(xf86OutputPtr output)
     I830OutputPrivatePtr intel_output = output->driver_private;
     struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
 
-    if (dev_priv->controlled_output == SDVO_OUTPUT_SVID0)
+    if (dev_priv->is_tv)
 	return i830_sdvo_get_tv_modes(output);
     else
 	return i830_sdvo_get_ddc_modes(output);
@@ -1278,6 +1345,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     char		    name[60];
     char		    *name_prefix;
     char		    *name_suffix;
+    struct i830_sdvo_tv_format tv_formats;
 
     output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL);
     if (!output)
@@ -1412,6 +1480,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 	dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
         output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
 	name_prefix="S-Video";
+	dev_priv->is_tv = TRUE;
     }
     else
     {
@@ -1425,6 +1494,22 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 		   bytes[0], bytes[1]);
 	name_prefix="Unknown";
     }
+
+    if (dev_priv->controlled_output == SDVO_OUTPUT_RGB0 ||
+	dev_priv->controlled_output == SDVO_OUTPUT_RGB1) {
+	uint8_t status;
+
+	/* Detect if an RGB device is actually a TV device.  This is the
+	 * case for our HDMI+S-Video SDVO card.
+	 */
+	i830_sdvo_write_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
+			    NULL, 0);
+	status = i830_sdvo_read_response(output,
+					 &tv_formats, sizeof(tv_formats));
+	if (status == SDVO_CMD_STATUS_SUCCESS)
+	    dev_priv->is_tv = TRUE;
+    }
+
     strcpy (name, name_prefix);
     strcat (name, name_suffix);
     if (!xf86OutputRename (output, name))
commit 3c1701797b61afaae826a78455079e2115483053
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Mar 31 10:04:18 2008 -0700

    Add WIP SDVO TV-out support.
    
    Doesn't include properties for selecting TV formats or picture enhancements,
    and totally untested.

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index f60e38c..6c23c15 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -59,7 +59,7 @@ struct i830_sdvo_priv {
     int output_device;
 
     /** Active outputs controlled by this SDVO output */
-    uint16_t active_outputs;
+    uint16_t controlled_output;
 
     /**
      * Capabilities of the SDVO device returned by i830_sdvo_get_capabilities()
@@ -692,7 +692,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
     output_dtd.part2.reserved = 0;
 
     /* Set the output timing to the screen */
-    i830_sdvo_set_target_output(output, dev_priv->active_outputs);
+    i830_sdvo_set_target_output(output, dev_priv->controlled_output);
     i830_sdvo_set_output_timing(output, &output_dtd);
 
     /* Set the input timing to the screen. Assume always input 0. */
@@ -800,7 +800,7 @@ i830_sdvo_dpms(xf86OutputPtr output, int mode)
 
 	if (0)
 	    i830_sdvo_set_encoder_power_state(output, mode);
-	i830_sdvo_set_active_outputs(output, dev_priv->active_outputs);
+	i830_sdvo_set_active_outputs(output, dev_priv->controlled_output);
     }
 }
 
@@ -1098,7 +1098,7 @@ i830_sdvo_detect(xf86OutputPtr output)
 }
 
 static DisplayModePtr
-i830_sdvo_get_modes(xf86OutputPtr output)
+i830_sdvo_get_ddc_modes(xf86OutputPtr output)
 {
     ScrnInfoPtr pScrn = output->scrn;
     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
@@ -1130,6 +1130,95 @@ i830_sdvo_get_modes(xf86OutputPtr output)
     return modes;
 }
 
+/**
+ * Constructs a DisplayModeRec for the given widht/height/refresh, which will
+ * be programmed into the display pipe.  The TV encoder's scaler will filter
+ * this to the format actually required by the display.
+ */
+static void
+i830_sdvo_get_tv_mode(DisplayModePtr *head, int width, int height,
+		      float refresh)
+{
+    DisplayModePtr mode;
+
+    mode = xcalloc(1, sizeof(*mode));
+    if (mode == NULL)
+	return;
+
+    mode->name = XNFprintf("%dx%d@%.2f", width, height, refresh);
+    mode->HDisplay = width;
+    mode->HSyncStart = width + 1;
+    mode->HSyncEnd = width + 64;
+    mode->HTotal = width + 96;
+
+    mode->VDisplay = height;
+    mode->VSyncStart = height + 1;
+    mode->VSyncEnd = height + 32;
+    mode->VTotal = height + 33;
+
+    mode->Clock = (int) (refresh * mode->VTotal * mode->HTotal / 1000.0);
+    mode->type = M_T_DRIVER;
+    mode->next = NULL;
+    mode->prev = NULL;
+
+    mode->next = NULL;
+    mode->prev = *head;
+    if (*head != NULL)
+	(*head)->next = mode;
+    else
+	*head = mode;
+}
+
+static DisplayModePtr
+i830_sdvo_get_tv_modes(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    DisplayModePtr modes = NULL;
+    struct i830_sdvo_sdtv_resolution_reply res;
+    uint8_t status;
+    float refresh = 60; /* XXX */
+
+    /* Read the list of supported input resolutions for the selected TV format.
+     */
+    i830_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, NULL, 0);
+    status = i830_sdvo_read_response(output, &res, sizeof(res));
+    if (status != SDVO_CMD_STATUS_SUCCESS)
+	return NULL;
+
+    if (res.res_320x200) i830_sdvo_get_tv_mode(&modes, 320, 200, refresh);
+    if (res.res_320x240) i830_sdvo_get_tv_mode(&modes, 320, 240, refresh);
+    if (res.res_400x300) i830_sdvo_get_tv_mode(&modes, 400, 300, refresh);
+    if (res.res_640x350) i830_sdvo_get_tv_mode(&modes, 640, 350, refresh);
+    if (res.res_640x400) i830_sdvo_get_tv_mode(&modes, 640, 400, refresh);
+    if (res.res_640x480) i830_sdvo_get_tv_mode(&modes, 640, 480, refresh);
+    if (res.res_704x480) i830_sdvo_get_tv_mode(&modes, 704, 480, refresh);
+    if (res.res_704x576) i830_sdvo_get_tv_mode(&modes, 704, 576, refresh);
+    if (res.res_720x350) i830_sdvo_get_tv_mode(&modes, 720, 350, refresh);
+    if (res.res_720x400) i830_sdvo_get_tv_mode(&modes, 720, 400, refresh);
+    if (res.res_720x480) i830_sdvo_get_tv_mode(&modes, 720, 480, refresh);
+    if (res.res_720x540) i830_sdvo_get_tv_mode(&modes, 720, 540, refresh);
+    if (res.res_720x576) i830_sdvo_get_tv_mode(&modes, 720, 576, refresh);
+    if (res.res_800x600) i830_sdvo_get_tv_mode(&modes, 800, 600, refresh);
+    if (res.res_832x624) i830_sdvo_get_tv_mode(&modes, 832, 624, refresh);
+    if (res.res_920x766) i830_sdvo_get_tv_mode(&modes, 920, 766, refresh);
+    if (res.res_1024x768) i830_sdvo_get_tv_mode(&modes, 1024, 768, refresh);
+    if (res.res_1280x1024) i830_sdvo_get_tv_mode(&modes, 1280, 1024, refresh);
+
+    return modes;
+}
+
+static DisplayModePtr
+i830_sdvo_get_modes(xf86OutputPtr output)
+{
+    I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+
+    if (dev_priv->controlled_output == SDVO_OUTPUT_SVID0)
+	return i830_sdvo_get_tv_modes(output);
+    else
+	return i830_sdvo_get_ddc_modes(output);
+}
+
 static void
 i830_sdvo_destroy (xf86OutputPtr output)
 {
@@ -1294,38 +1383,44 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 
     i830_sdvo_get_capabilities(output, &dev_priv->caps);
 
-    memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs));
     if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
     {
-	dev_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+	dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="TMDS";
     }
     else if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)
     {
-	dev_priv->active_outputs = SDVO_OUTPUT_TMDS1;
+	dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="TMDS";
     }
     else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
     {
-	dev_priv->active_outputs = SDVO_OUTPUT_RGB0;
+	dev_priv->controlled_output = SDVO_OUTPUT_RGB0;
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="VGA";
     }
     else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
     {
-	dev_priv->active_outputs = SDVO_OUTPUT_RGB1;
+	dev_priv->controlled_output = SDVO_OUTPUT_RGB1;
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="VGA";
     }
+    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
+        output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
+	name_prefix="S-Video";
+    }
     else
     {
 	unsigned char	bytes[2];
 
+	dev_priv->controlled_output = 0;
 	memcpy (bytes, &dev_priv->caps.output_flags, 2);
-	xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_ERROR,
-		   "%s: No active TMDS outputs (0x%02x%02x)\n",
+	xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING,
+		   "%s: Unknown SDVO output type (0x%02x%02x)\n",
 		   SDVO_NAME(dev_priv),
 		   bytes[0], bytes[1]);
 	name_prefix="Unknown";
commit 9d5ba26fb5c337388920b45eadda85e43bc564fa
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Mar 28 14:28:28 2008 -0700

    Add SDVO TV-out registers.

diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index 725460f..63688ac 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -306,11 +306,107 @@ struct i830_sdvo_set_target_input_args {
 # define SDVO_CLOCK_RATE_MULT_4X				(1 << 3)
 
 #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS		0x27
+/** 5 bytes of bit flags for TV formats shared by all TV format functions */
+struct i830_sdvo_tv_format {
+    unsigned int ntsc_m:1;
+    unsigned int ntsc_j:1;
+    unsigned int ntsc_443:1;
+    unsigned int pal_b:1;
+    unsigned int pal_d:1;
+    unsigned int pal_g:1;
+    unsigned int pal_h:1;
+    unsigned int pal_i:1;
+
+    unsigned int pal_m:1;
+    unsigned int pal_n:1;
+    unsigned int pal_nc:1;
+    unsigned int pal_60:1;
+    unsigned int secam_b:1;
+    unsigned int secam_d:1;
+    unsigned int secam_g:1;
+    unsigned int secam_k:1;
+
+    unsigned int secam_k1:1;
+    unsigned int secam_l:1;
+    unsigned int secam_60:1;
+    unsigned int hdtv_std_smpte_240m_1080i_59:1;
+    unsigned int hdtv_std_smpte_240m_1080i_60:1;
+    unsigned int hdtv_std_smpte_260m_1080i_59:1;
+    unsigned int hdtv_std_smpte_260m_1080i_60:1;
+    unsigned int hdtv_std_smpte_270m_1080i_50:1;
+
+    unsigned int hdtv_std_smpte_274m_1080i_50:1;
+    unsigned int hdtv_std_smpte_274m_1080i_59:1;
+    unsigned int hdtv_std_smpte_274m_1080i_60:1;
+    unsigned int hdtv_std_smpte_274m_1080p_23:1;
+    unsigned int hdtv_std_smpte_274m_1080p_24:1;
+    unsigned int hdtv_std_smpte_274m_1080p_25:1;
+    unsigned int hdtv_std_smpte_274m_1080p_29:1;
+    unsigned int hdtv_std_smpte_274m_1080p_50:1;
+
+    unsigned int hdtv_std_smpte_274m_1080p_59:1;
+    unsigned int hdtv_std_smpte_274m_1080p_60:1;
+    unsigned int hdtv_std_smpte_295m_1080i_50:1;
+    unsigned int hdtv_std_smpte_295m_1080p_50:1;
+    unsigned int hdtv_std_smpte_296m_720p_59:1;
+    unsigned int hdtv_std_smpte_296m_720p_60:1;
+    unsigned int hdtv_std_smpte_296m_720p_50:1;
+    unsigned int hdtv_std_smpte_293m_480p_59:1;
+
+    unsigned int hdtv_std_smpte_270m_480i_59:1;
+    unsigned int hdtv_std_iturbt601_576i_50:1;
+    unsigned int hdtv_std_iturbt601_576p_50:1;
+    unsigned int hdtv_std_eia_7702a_480i_60:1;
+    unsigned int hdtv_std_eia_7702a_480p_60:1;
+    unsigned int pad:3;
+} __attribute__((packed));
 
 #define SDVO_CMD_GET_TV_FORMAT				0x28
 
+/** This command should be run before SetOutputTimingsPart[12] */
 #define SDVO_CMD_SET_TV_FORMAT				0x29
 
+/** Returns the resolutiosn that can be used with the given TV format */
+#define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT		0x83
+struct i830_sdvo_sdtv_resolution_request {
+    unsigned int ntsc_m:1;
+    unsigned int ntsc_j:1;
+    unsigned int ntsc_443:1;
+    unsigned int pal_b:1;
+    unsigned int pal_d:1;
+    unsigned int pal_g:1;
+    unsigned int pal_h:1;
+    unsigned int pal_i:1;
+
+    unsigned int pal_m:1;
+    unsigned int pal_n:1;
+    unsigned int pal_nc:1;
+    unsigned int pal_60:1;
+} __attribute__((packed));
+struct i830_sdvo_sdtv_resolution_reply {
+    unsigned int res_320x200:1;
+    unsigned int res_320x240:1;
+    unsigned int res_400x300:1;
+    unsigned int res_640x350:1;
+    unsigned int res_640x400:1;
+    unsigned int res_640x480:1;
+    unsigned int res_704x480:1;
+    unsigned int res_704x576:1;
+
+    unsigned int res_720x350:1;
+    unsigned int res_720x400:1;
+    unsigned int res_720x480:1;
+    unsigned int res_720x540:1;
+    unsigned int res_720x576:1;
+    unsigned int res_800x600:1;
+    unsigned int res_832x624:1;
+
+    unsigned int res_920x766:1;
+    unsigned int res_1024x768:1;
+    unsigned int res_1280x1024:1;
+    unsigned int pad:5;
+} __attribute__((packed));
+
 #define SDVO_CMD_GET_SUPPORTED_POWER_STATES		0x2a
 #define SDVO_CMD_GET_ENCODER_POWER_STATE		0x2b
 #define SDVO_CMD_SET_ENCODER_POWER_STATE		0x2c
@@ -319,6 +415,91 @@ struct i830_sdvo_set_target_input_args {
 # define SDVO_ENCODER_STATE_SUSPEND				(1 << 2)
 # define SDVO_ENCODER_STATE_OFF					(1 << 3)
 
+#define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS		0x84
+struct i830_sdvo_enhancements_reply {
+    unsigned int flicker_filter:1;
+    unsigned int flicker_filter_adaptive:1;
+    unsigned int flicker_filter_2d:1;
+    unsigned int saturation:1;
+    unsigned int hue:1;
+    unsigned int brightness:1;
+    unsigned int contrast:1;
+    unsigned int overscan_h:1;
+
+    unsigned int overscan_v:1;
+    unsigned int position_h:1;
+    unsigned int position_v:1;
+    unsigned int sharpness:1;
+    unsigned int dot_crawl:1;
+    unsigned int dither:1;
+    unsigned int max_tv_chroma_filter:1;
+    unsigned int max_tv_luma_filter:1;
+} __attribute__((packed));
+
+/* Picture enhancement limits below are dependent on the current TV format,
+ * and thus need to be queried and set after it.
+ */
+#define SDVO_CMD_GET_MAX_FLICKER_FITER			0x4d
+#define SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FITER		0x7b
+#define SDVO_CMD_GET_MAX_2D_FLICKER_FITER		0x52
+#define SDVO_CMD_GET_MAX_SATURATION			0x55
+#define SDVO_CMD_GET_MAX_HUE				0x58
+#define SDVO_CMD_GET_MAX_BRIGHTNESS			0x5c
+#define SDVO_CMD_GET_MAX_CONTRAST			0x5e
+#define SDVO_CMD_GET_MAX_OVERSCAN_H			0x61
+#define SDVO_CMD_GET_MAX_OVERSCAN_V			0x64
+#define SDVO_CMD_GET_MAX_POSITION_H			0x67
+#define SDVO_CMD_GET_MAX_POSITION_V			0x6a
+#define SDVO_CMD_GET_MAX_SHARPNESS_V			0x6d
+#define SDVO_CMD_GET_MAX_TV_CHROMA			0x74
+#define SDVO_CMD_GET_MAX_TV_LUMA			0x77
+struct i830_sdvo_enhancement_limits_reply {
+    uint16_t max_value;
+    uint16_t default_value;
+} __attribute__((packed));
+
+#define SDVO_CMD_GET_FLICKER_FITER			0x4d
+#define SDVO_CMD_SET_FLICKER_FITER			0x4e
+#define SDVO_CMD_GET_ADAPTIVE_FLICKER_FITER		0x50
+#define SDVO_CMD_SET_ADAPTIVE_FLICKER_FITER		0x51
+#define SDVO_CMD_GET_2D_FLICKER_FITER			0x53
+#define SDVO_CMD_SET_2D_FLICKER_FITER			0x54
+#define SDVO_CMD_GET_SATURATION				0x56
+#define SDVO_CMD_SET_SATURATION				0x57
+#define SDVO_CMD_GET_HUE				0x59
+#define SDVO_CMD_SET_HUE				0x5a
+#define SDVO_CMD_GET_BRIGHTNESS				0x5c
+#define SDVO_CMD_SET_BRIGHTNESS				0x5d
+#define SDVO_CMD_GET_CONTRAST				0x5f
+#define SDVO_CMD_SET_CONTRAST				0x60
+#define SDVO_CMD_GET_OVERSCAN_H				0x62
+#define SDVO_CMD_SET_OVERSCAN_H				0x63
+#define SDVO_CMD_GET_OVERSCAN_V				0x65
+#define SDVO_CMD_SET_OVERSCAN_V				0x66
+#define SDVO_CMD_GET_POSITION_H				0x68
+#define SDVO_CMD_SET_POSITION_H				0x69
+#define SDVO_CMD_GET_POSITION_V				0x6b
+#define SDVO_CMD_SET_POSITION_V				0x6c
+#define SDVO_CMD_GET_SHARPNESS				0x6e
+#define SDVO_CMD_SET_SHARPNESS				0x6f
+#define SDVO_CMD_GET_TV_CHROMA				0x75
+#define SDVO_CMD_SET_TV_CHROMA				0x76
+#define SDVO_CMD_GET_TV_LUMA				0x78
+#define SDVO_CMD_SET_TV_LUMA				0x79
+struct i830_sdvo_enhancements_arg {
+    uint16_t value;
+}__attribute__((packed));
+
+#define SDVO_CMD_GET_DOT_CRAWL				0x70
+#define SDVO_CMD_SET_DOT_CRAWL				0x71
+# define SDVO_DOT_CRAWL_ON					(1 << 0)
+# define SDVO_DOT_CRAWL_DEFAULT_ON				(1 << 1)
+
+#define SDVO_CMD_GET_DITHER				0x72
+#define SDVO_CMD_SET_DITHER				0x73
+# define SDVO_DITHER_ON						(1 << 0)
+# define SDVO_DITHER_DEFAULT_ON					(1 << 1)
+
 #define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93
 
 #define SDVO_CMD_SET_CONTROL_BUS_SWITCH			0x7a


More information about the xorg-commit mailing list