From: Michael Hunold (LinuxTV.org CVS maintainer) <hunold@linuxtv.org>
To: linux-kernel@vger.kernel.org
Subject: [PATCH 3/14] add new DVB-T frontend driver
Date: Wed, 8 Oct 2003 15:28:48 +0200 [thread overview]
Message-ID: <1065619728592@convergence.de> (raw)
In-Reply-To: <10656197272107@convergence.de>
- [DVB] add new DVB-T frontend driver sp887x.c
diff -uNrwB --new-file xx-linux-2.6.0-test5/drivers/media/dvb/frontends/Makefile linux-2.6.0-test5/drivers/media/dvb/frontends/Makefile
--- xx-linux-2.6.0-test5/drivers/media/dvb/frontends/Makefile 2003-09-10 11:28:54.000000000 +0200
+++ linux-2.6.0-test5/drivers/media/dvb/frontends/Makefile 2003-09-09 09:24:21.000000000 +0200
@@ -15,3 +15,4 @@
obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
+obj-$(CONFIG_DVB_SP887X) += sp887x.o
diff -uNrwB --new-file xx-linux-2.6.0-test5/drivers/media/dvb/frontends/sp887x.c linux-2.6.0-test5/drivers/media/dvb/frontends/sp887x.c
--- xx-linux-2.6.0-test5/drivers/media/dvb/frontends/sp887x.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test5/drivers/media/dvb/frontends/sp887x.c 2003-09-07 17:40:35.000000000 +0200
@@ -0,0 +1,610 @@
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+#include "dvb_compat.h"
+
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#if 0
+#define LOG(dir,addr,buf,len) \
+ do { \
+ int i; \
+ printk("%s (%02x):", dir, addr & 0xff); \
+ for (i=0; i<len; i++) \
+ printk(" 0x%02x,", buf[i] & 0xff); \
+ printk("\n"); \
+ } while (0)
+#else
+#define LOG(dir,addr,buf,len)
+#endif
+
+
+static
+struct dvb_frontend_info sp887x_info = {
+ .name = "Microtune MT7072DTF",
+ .type = FE_OFDM,
+ .frequency_min = 50500000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_RECOVER
+};
+
+
+
+static
+int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
+{
+ struct dvb_i2c_bus *i2c = fe->i2c;
+ struct i2c_msg msg = { addr: addr, flags: 0, buf: buf, len: len };
+ int err;
+
+ LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
+
+ if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+ printk ("%s: i2c write error (addr %02x, err == %i)\n",
+ __FUNCTION__, addr, err);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+
+
+static
+int sp887x_writereg (struct dvb_frontend *fe, u16 reg, u16 data)
+{
+ struct dvb_i2c_bus *i2c = fe->i2c;
+ u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
+ struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 };
+ int ret;
+
+ LOG("sp887x_writereg", msg.addr, msg.buf, msg.len);
+
+ if ((ret = i2c->xfer(i2c, &msg, 1)) != 1) {
+ /**
+ * in case of soft reset we ignore ACK errors...
+ */
+ if (!(reg == 0xf1a && data == 0x000 &&
+ (ret == -EREMOTEIO || ret == -EFAULT)))
+ {
+ printk("%s: writereg error "
+ "(reg %03x, data %03x, ret == %i)\n",
+ __FUNCTION__, reg & 0xffff, data & 0xffff, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+
+static
+u16 sp887x_readreg (struct dvb_frontend *fe, u16 reg)
+{
+ struct dvb_i2c_bus *i2c = fe->i2c;
+ u8 b0 [] = { reg >> 8 , reg & 0xff };
+ u8 b1 [2];
+ int ret;
+ struct i2c_msg msg[] = {{ .addr = 0x70, .flags = 0, .buf = b0, .len = 2 },
+ { .addr = 0x70, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
+
+ LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len);
+ LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len);
+
+ if ((ret = i2c->xfer(i2c, msg, 2)) != 2)
+ printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+ return (((b1[0] << 8) | b1[1]) & 0xfff);
+}
+
+
+static
+void sp887x_microcontroller_stop (struct dvb_frontend *fe)
+{
+ sp887x_writereg(fe, 0xf08, 0x000);
+ sp887x_writereg(fe, 0xf09, 0x000);
+
+ /* microcontroller STOP */
+ sp887x_writereg(fe, 0xf00, 0x000);
+}
+
+
+static
+void sp887x_microcontroller_start (struct dvb_frontend *fe)
+{
+ sp887x_writereg(fe, 0xf08, 0x000);
+ sp887x_writereg(fe, 0xf09, 0x000);
+
+ /* microcontroller START */
+ sp887x_writereg(fe, 0xf00, 0x001);
+}
+
+
+static
+void sp887x_setup_agc (struct dvb_frontend *fe)
+{
+ /* setup AGC parameters */
+ sp887x_writereg(fe, 0x33c, 0x054);
+ sp887x_writereg(fe, 0x33b, 0x04c);
+ sp887x_writereg(fe, 0x328, 0x000);
+ sp887x_writereg(fe, 0x327, 0x005);
+ sp887x_writereg(fe, 0x326, 0x001);
+ sp887x_writereg(fe, 0x325, 0x001);
+ sp887x_writereg(fe, 0x324, 0x001);
+ sp887x_writereg(fe, 0x318, 0x050);
+ sp887x_writereg(fe, 0x317, 0x3fe);
+ sp887x_writereg(fe, 0x316, 0x001);
+ sp887x_writereg(fe, 0x313, 0x005);
+ sp887x_writereg(fe, 0x312, 0x002);
+ sp887x_writereg(fe, 0x306, 0x000);
+ sp887x_writereg(fe, 0x303, 0x000);
+}
+
+
+#include "sp887x_firm.h"
+
+#define BLOCKSIZE 30
+
+/**
+ * load firmware and setup MPEG interface...
+ */
+static
+int sp887x_initial_setup (struct dvb_frontend *fe)
+{
+ u8 buf [BLOCKSIZE];
+ int i;
+
+ /* soft reset */
+ sp887x_writereg(fe, 0xf1a, 0x000);
+
+ sp887x_microcontroller_stop (fe);
+
+ printk ("%s: firmware upload... ", __FUNCTION__);
+
+ /* setup write pointer to -1 (end of memory) */
+ /* bit 0x8000 in address is set to enable 13bit mode */
+ sp887x_writereg(fe, 0x8f08, 0x1fff);
+
+ /* dummy write (wrap around to start of memory) */
+ sp887x_writereg(fe, 0x8f0a, 0x0000);
+
+ for (i=0; i<sizeof(sp887x_firm); i+=BLOCKSIZE) {
+ int c = BLOCKSIZE;
+ int err;
+
+ if (i+c > sizeof(sp887x_firm))
+ c = sizeof(sp887x_firm) - i;
+
+ /* bit 0x8000 in address is set to enable 13bit mode */
+ /* bit 0x4000 enables multibyte read/write transfers */
+ /* write register is 0xf0a */
+ buf[0] = 0xcf;
+ buf[1] = 0x0a;
+
+ memcpy(&buf[2], &sp887x_firm[i], c);
+
+ if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) {
+ printk ("failed.\n");
+ printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+ return err;
+ }
+ }
+
+ /* don't write RS bytes between packets */
+ sp887x_writereg(fe, 0xc13, 0x001);
+
+ /* suppress clock if (!data_valid) */
+ sp887x_writereg(fe, 0xc14, 0x000);
+
+ /* setup MPEG interface... */
+ sp887x_writereg(fe, 0xc1a, 0x872);
+ sp887x_writereg(fe, 0xc1b, 0x001);
+ sp887x_writereg(fe, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
+ sp887x_writereg(fe, 0xc1a, 0x871);
+
+ /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
+ sp887x_writereg(fe, 0x301, 0x002);
+
+ sp887x_setup_agc(fe);
+
+ /* bit 0x010: enable data valid signal */
+ sp887x_writereg(fe, 0xd00, 0x010);
+ sp887x_writereg(fe, 0x0d1, 0x000);
+
+ printk ("done.\n");
+ return 0;
+};
+
+
+/**
+ * returns the actual tuned center frequency which can be used
+ * to initialise the AFC registers
+ */
+static
+int tsa5060_setup_pll (struct dvb_frontend *fe, int freq)
+{
+ u8 cfg, cpump, band_select;
+ u8 buf [4];
+ u32 div;
+
+ div = (36000000 + freq + 83333) / 166666;
+ cfg = 0x88;
+
+ cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 :
+ freq < 470000000 ? 2 : freq < 750000000 ? 2 : 3;
+
+ band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03;
+
+ buf [0] = (div >> 8) & 0x7f;
+ buf [1] = div & 0xff;
+ buf [2] = ((div >> 10) & 0x60) | cfg;
+ buf [3] = cpump | band_select;
+
+ /* open i2c gate for PLL message transmission... */
+ sp887x_writereg(fe, 0x206, 0x001);
+ i2c_writebytes(fe, 0x60, buf, 4);
+ sp887x_writereg(fe, 0x206, 0x000);
+
+ return (div * 166666 - 36000000);
+}
+
+
+
+static
+int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+{
+ int known_parameters = 1;
+
+ *reg0xc05 = 0x000;
+
+ switch (p->u.ofdm.constellation) {
+ case QPSK:
+ break;
+ case QAM_16:
+ *reg0xc05 |= (1 << 10);
+ break;
+ case QAM_64:
+ *reg0xc05 |= (2 << 10);
+ break;
+ case QAM_AUTO:
+ known_parameters = 0;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ switch (p->u.ofdm.hierarchy_information) {
+ case HIERARCHY_NONE:
+ break;
+ case HIERARCHY_1:
+ *reg0xc05 |= (1 << 7);
+ break;
+ case HIERARCHY_2:
+ *reg0xc05 |= (2 << 7);
+ break;
+ case HIERARCHY_4:
+ *reg0xc05 |= (3 << 7);
+ break;
+ case HIERARCHY_AUTO:
+ known_parameters = 0;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ switch (p->u.ofdm.code_rate_HP) {
+ case FEC_1_2:
+ break;
+ case FEC_2_3:
+ *reg0xc05 |= (1 << 3);
+ break;
+ case FEC_3_4:
+ *reg0xc05 |= (2 << 3);
+ break;
+ case FEC_5_6:
+ *reg0xc05 |= (3 << 3);
+ break;
+ case FEC_7_8:
+ *reg0xc05 |= (4 << 3);
+ break;
+ case FEC_AUTO:
+ known_parameters = 0;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ if (known_parameters)
+ *reg0xc05 |= (2 << 1); /* use specified parameters */
+ else
+ *reg0xc05 |= (1 << 1); /* enable autoprobing */
+
+ return 0;
+}
+
+
+/**
+ * estimates division of two 24bit numbers,
+ * derived from the ves1820/stv0299 driver code
+ */
+static
+void divide (int n, int d, int *quotient_i, int *quotient_f)
+{
+ unsigned int q, r;
+
+ r = (n % d) << 8;
+ q = (r / d);
+
+ if (quotient_i)
+ *quotient_i = q;
+
+ if (quotient_f) {
+ r = (r % d) << 8;
+ q = (q << 8) | (r / d);
+ r = (r % d) << 8;
+ *quotient_f = (q << 8) | (r / d);
+ }
+}
+
+
+static
+void sp887x_correct_offsets (struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p,
+ int actual_freq)
+{
+ static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
+ int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+ int freq_offset = actual_freq - p->frequency;
+ int sysclock = 61003; //[kHz]
+ int ifreq = 36000000;
+ int freq;
+ int frequency_shift;
+
+ if (p->inversion == INVERSION_ON)
+ freq = ifreq - freq_offset;
+ else
+ freq = ifreq + freq_offset;
+
+ divide(freq / 333, sysclock, NULL, &frequency_shift);
+
+ if (p->inversion == INVERSION_ON)
+ frequency_shift = -frequency_shift;
+
+ /* sample rate correction */
+ sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12);
+ sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff);
+
+ /* carrier offset correction */
+ sp887x_writereg(fe, 0x309, frequency_shift >> 12);
+ sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);
+}
+
+
+static
+int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ int actual_freq, err;
+ u16 val, reg0xc05;
+
+ if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ &&
+ p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ &&
+ p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ)
+ return -EINVAL;
+
+ if ((err = configure_reg0xc05(p, ®0xc05)))
+ return err;
+
+ sp887x_microcontroller_stop(fe);
+
+ actual_freq = tsa5060_setup_pll(fe, p->frequency);
+
+ /* read status reg in order to clear pending irqs */
+ sp887x_readreg(fe, 0x200);
+
+ sp887x_correct_offsets(fe, p, actual_freq);
+
+ /* filter for 6/7/8 Mhz channel */
+ if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+ val = 2;
+ else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+ val = 1;
+ else
+ val = 0;
+
+ sp887x_writereg(fe, 0x311, val);
+
+ /* scan order: 2k first = 0, 8k first = 1 */
+ if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+ sp887x_writereg(fe, 0x338, 0x000);
+ else
+ sp887x_writereg(fe, 0x338, 0x001);
+
+ sp887x_writereg(fe, 0xc05, reg0xc05);
+
+ if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+ val = 2 << 3;
+ else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+ val = 3 << 3;
+ else
+ val = 0 << 3;
+
+ /* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
+ * optimize algorithm for given bandwidth...
+ */
+ sp887x_writereg(fe, 0xf14, 0x160 | val);
+ sp887x_writereg(fe, 0xf15, 0x000);
+
+ sp887x_microcontroller_start(fe);
+ return 0;
+}
+
+
+static
+int sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case FE_GET_INFO:
+ memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info));
+ break;
+
+ case FE_READ_STATUS:
+ {
+ u16 snr12 = sp887x_readreg(fe, 0xf16);
+ u16 sync0x200 = sp887x_readreg(fe, 0x200);
+ u16 sync0xf17 = sp887x_readreg(fe, 0xf17);
+ fe_status_t *status = arg;
+
+ *status = 0;
+
+ if (snr12 > 0x00f)
+ *status |= FE_HAS_SIGNAL;
+
+ //if (sync0x200 & 0x004)
+ // *status |= FE_HAS_SYNC | FE_HAS_CARRIER;
+
+ //if (sync0x200 & 0x008)
+ // *status |= FE_HAS_VITERBI;
+
+ if ((sync0xf17 & 0x00f) == 0x002) {
+ *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
+ }
+
+ if (sync0x200 & 0x001) { /* tuner adjustment requested...*/
+ int steps = (sync0x200 >> 4) & 0x00f;
+ if (steps & 0x008)
+ steps = -steps;
+ dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
+ steps);
+ }
+
+ break;
+
+ }
+
+ case FE_READ_BER:
+ {
+ u32* ber = arg;
+ *ber = (sp887x_readreg(fe, 0xc08) & 0x3f) |
+ (sp887x_readreg(fe, 0xc07) << 6);
+ sp887x_writereg(fe, 0xc08, 0x000);
+ sp887x_writereg(fe, 0xc07, 0x000);
+ if (*ber >= 0x3fff0)
+ *ber = ~0;
+ break;
+
+ }
+
+ case FE_READ_SIGNAL_STRENGTH: // FIXME: correct registers ?
+ {
+ u16 snr12 = sp887x_readreg(fe, 0xf16);
+ u32 signal = 3 * (snr12 << 4);
+ *((u16*) arg) = (signal < 0xffff) ? signal : 0xffff;
+ break;
+ }
+
+ case FE_READ_SNR:
+ {
+ u16 snr12 = sp887x_readreg(fe, 0xf16);
+ *(u16*) arg = (snr12 << 4) | (snr12 >> 8);
+ break;
+ }
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ {
+ u32 *ublocks = (u32 *) arg;
+ *ublocks = sp887x_readreg(fe, 0xc0c);
+ if (*ublocks == 0xfff)
+ *ublocks = ~0;
+ break;
+ }
+
+ case FE_SET_FRONTEND:
+ return sp887x_setup_frontend_parameters(fe, arg);
+
+ case FE_GET_FRONTEND: // FIXME: read known values back from Hardware...
+ break;
+
+ case FE_SLEEP:
+ /* tristate TS output and disable interface pins */
+ sp887x_writereg(fe, 0xc18, 0x000);
+ break;
+
+ case FE_INIT:
+ if (fe->data == NULL) { /* first time initialisation... */
+ fe->data = (void*) ~0;
+ sp887x_initial_setup (fe);
+ }
+ /* enable TS output and interface pins */
+ sp887x_writereg(fe, 0xc18, 0x00d);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ };
+
+ return 0;
+}
+
+
+
+static
+int sp887x_attach (struct dvb_i2c_bus *i2c)
+{
+ struct i2c_msg msg = { addr: 0x70, flags: 0, buf: NULL, len: 0 };
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (i2c->xfer (i2c, &msg, 1) != 1)
+ return -ENODEV;
+
+ dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
+
+ return 0;
+}
+
+
+static
+void sp887x_detach (struct dvb_i2c_bus *i2c)
+{
+ dprintk ("%s\n", __FUNCTION__);
+ dvb_unregister_frontend (sp887x_ioctl, i2c);
+}
+
+
+static
+int __init init_sp887x (void)
+{
+ dprintk ("%s\n", __FUNCTION__);
+ return dvb_register_i2c_device (NULL, sp887x_attach, sp887x_detach);
+}
+
+
+static
+void __exit exit_sp887x (void)
+{
+ dprintk ("%s\n", __FUNCTION__);
+ dvb_unregister_i2c_device (sp887x_attach);
+}
+
+
+module_init(init_sp887x);
+module_exit(exit_sp887x);
+
+
+MODULE_DESCRIPTION("sp887x DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
+
+
next prev parent reply other threads:[~2003-10-08 13:37 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-10-08 13:28 [PATCH 1/14] LinuxTV.org DVB driver update Michael Hunold
2003-10-08 13:28 ` [PATCH 2/14] firmware update for av7110 dvb driver Michael Hunold
2003-10-08 13:28 ` Michael Hunold [this message]
2003-10-08 13:28 ` [PATCH 4/14] video capture updates for saa7146 core Michael Hunold
2003-10-08 13:28 ` [PATCH 5/14] multiple device *read* opens support Michael Hunold
2003-10-08 13:28 ` [PATCH 6/14] update copyright and licensing Michael Hunold
2003-10-08 13:28 ` [PATCH 7/14] usual c99 initializer fixes Michael Hunold
2003-10-08 13:28 ` [PATCH 8/14] various patches for non-av7110 dvb-drivers Michael Hunold
2003-10-08 13:28 ` [PATCH 9/14] various av7110 dvb-driver updates Michael Hunold
2003-10-08 13:28 ` [PATCH 10/14] update dvb frontend drivers Michael Hunold
2003-10-08 13:28 ` [PATCH 11/14] Kconfig and Makefile updates, inspired by Adrian Bunk and Roman Zippel Michael Hunold
2003-10-08 13:28 ` [PATCH 12/14] some more av7110 dvb-driver updates Michael Hunold
2003-10-08 13:29 ` [PATCH 13/14] fix v4l1 backward compatibility in saa7146 driver Michael Hunold
2003-10-08 13:29 ` [PATCH 14/14] firmware blob for new DVB-T frontend driver Michael Hunold
2003-10-08 14:45 ` [PATCH 2/14] firmware update for av7110 dvb driver Marcel Holtmann
2003-10-08 15:36 ` Michael Hunold
2003-10-08 15:54 ` Michael Hunold
2003-10-12 21:42 ` Manuel Estrada Sainz
2003-10-11 11:59 ` Jochen Friedrich
2003-10-10 20:15 ` [PATCH 1/14] LinuxTV.org DVB driver update Stephen Hemminger
2003-10-11 8:41 ` Michael Hunold
2003-10-11 17:53 ` David S. Miller
2003-10-12 9:16 ` Geert Uytterhoeven
2003-10-12 11:08 ` Sam Ravnborg
2003-10-12 20:14 ` Michael Hunold
2003-10-13 16:01 ` Stephen Hemminger
2003-10-14 9:59 ` Michael Hunold
2003-10-12 20:10 ` Michael Hunold
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1065619728592@convergence.de \
--to=hunold@linuxtv.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.