All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brad Love <brad@nextdimension.cc>
To: linux-media@vger.kernel.org
Cc: Brad Love <brad@nextdimension.cc>
Subject: [PATCH 1/9] em28xx: Hauppauge DualHD second tuner functionality
Date: Thu,  4 Jan 2018 18:04:11 -0600	[thread overview]
Message-ID: <1515110659-20145-2-git-send-email-brad@nextdimension.cc> (raw)
In-Reply-To: <1515110659-20145-1-git-send-email-brad@nextdimension.cc>

Implement use of secondary TS port on em28xx.
Adds has_dual_ts field, allows secondary demod/tuner to be
added to a single em28xx device.

Hauppauge DualHD models are configured to use this feature.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 126 +++++++++++++++++++++++++++++++-
 drivers/media/usb/em28xx/em28xx-core.c  |  42 +++++++++--
 drivers/media/usb/em28xx/em28xx-dvb.c   |  33 +++++++--
 drivers/media/usb/em28xx/em28xx.h       |  12 +++
 4 files changed, 196 insertions(+), 17 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 34e16f6a..7f5d0b28 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2402,6 +2402,7 @@ struct em28xx_board em28xx_boards[] = {
 		.tuner_type    = TUNER_ABSENT,
 		.tuner_gpio    = hauppauge_dualhd_dvb,
 		.has_dvb       = 1,
+		.has_dual_ts   = 1,
 		.ir_codes      = RC_MAP_HAUPPAUGE,
 		.leds          = hauppauge_dualhd_leds,
 	},
@@ -2417,6 +2418,7 @@ struct em28xx_board em28xx_boards[] = {
 		.tuner_type    = TUNER_ABSENT,
 		.tuner_gpio    = hauppauge_dualhd_dvb,
 		.has_dvb       = 1,
+		.has_dual_ts   = 1,
 		.ir_codes      = RC_MAP_HAUPPAUGE,
 		.leds          = hauppauge_dualhd_leds,
 	},
@@ -3239,7 +3241,8 @@ static void em28xx_release_resources(struct em28xx *dev)
 		em28xx_i2c_unregister(dev, 1);
 	em28xx_i2c_unregister(dev, 0);
 
-	usb_put_dev(udev);
+	if (dev->ts == PRIMARY_TS)
+		usb_put_dev(udev);
 
 	/* Mark device as unused */
 	clear_bit(dev->devno, em28xx_devused);
@@ -3432,6 +3435,35 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 	return 0;
 }
 
+int em28xx_duplicate_dev(struct em28xx *dev)
+{
+	int nr;
+	struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL);
+
+	if (sec_dev == NULL) {
+		dev->dev_next = NULL;
+		return -ENOMEM;
+	}
+	memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev)));
+	/* Check to see next free device and mark as used */
+	do {
+		nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
+		if (nr >= EM28XX_MAXBOARDS) {
+			/* No free device slots */
+			dev_warn(&dev->intf->dev, ": Supports only %i em28xx boards.\n",
+					EM28XX_MAXBOARDS);
+			kfree(sec_dev);
+			dev->dev_next = NULL;
+			return -ENOMEM;
+		}
+	} while (test_and_set_bit(nr, em28xx_devused));
+	sec_dev->devno = nr;
+	snprintf(sec_dev->name, 28, "em28xx #%d", nr);
+	sec_dev->dev_next = NULL;
+	dev->dev_next = sec_dev;
+	return 0;
+}
+
 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
 
@@ -3551,6 +3583,17 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 						}
 					}
 					break;
+				case 0x85:
+					if (usb_endpoint_xfer_isoc(e)) {
+						if (size > dev->dvb_max_pkt_size_isoc_ts2) {
+							dev->dvb_ep_isoc_ts2 = e->bEndpointAddress;
+							dev->dvb_max_pkt_size_isoc_ts2 = size;
+							dev->dvb_alt_isoc = i;
+						}
+					} else {
+						dev->dvb_ep_bulk_ts2 = e->bEndpointAddress;
+					}
+					break;
 				}
 			}
 			/* NOTE:
@@ -3565,6 +3608,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 			 *  0x83	isoc*		=> audio
 			 *  0x84	isoc		=> digital
 			 *  0x84	bulk		=> analog or digital**
+			 *  0x85	isoc		=> digital TS2
+			 *  0x85	bulk		=> digital TS2
 			 * (*: audio should always be isoc)
 			 * (**: analog, if ep 0x82 is isoc, otherwise digital)
 			 *
@@ -3632,6 +3677,10 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	dev->has_video = has_video;
 	dev->ifnum = ifnum;
 
+	dev->ts = PRIMARY_TS;
+	snprintf(dev->name, 28, "em28xx");
+	dev->dev_next = NULL;
+
 	if (has_vendor_audio) {
 		dev_err(&interface->dev,
 			"Audio interface %i found (Vendor Class)\n", ifnum);
@@ -3711,6 +3760,65 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 			dev->dvb_xfer_bulk ? "bulk" : "isoc");
 	}
 
+	if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) {
+		dev->dev_next->ts = SECONDARY_TS;
+		dev->dev_next->alt   = -1;
+		dev->dev_next->is_audio_only = has_vendor_audio &&
+						!(has_video || has_dvb);
+		dev->dev_next->has_video = false;
+		dev->dev_next->ifnum = ifnum;
+		dev->dev_next->model = id->driver_info;
+
+		mutex_init(&dev->dev_next->lock);
+		retval = em28xx_init_dev(dev->dev_next, udev, interface,
+					dev->dev_next->devno);
+		if (retval)
+			goto err_free;
+
+		dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */
+		dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */
+
+		if (usb_xfer_mode < 0) {
+			if (dev->dev_next->board.is_webcam)
+				try_bulk = 1;
+			else
+				try_bulk = 0;
+		} else {
+			try_bulk = usb_xfer_mode > 0;
+		}
+
+		/* Select USB transfer types to use */
+		if (has_dvb) {
+			if (!dev->dvb_ep_isoc_ts2 ||
+			   (try_bulk && dev->dvb_ep_bulk_ts2))
+				dev->dev_next->dvb_xfer_bulk = 1;
+			dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n",
+				dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc");
+		}
+
+		dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2;
+		dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2;
+		dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
+		dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
+
+		/* Configuare hardware to support TS2*/
+		if (dev->dvb_xfer_bulk) {
+			/* The ep4 and ep5 are configuared for BULK */
+			em28xx_write_reg(dev, 0x0b, 0x96);
+			mdelay(100);
+			em28xx_write_reg(dev, 0x0b, 0x80);
+			mdelay(100);
+		} else {
+			/* The ep4 and ep5 are configuared for ISO */
+			em28xx_write_reg(dev, 0x0b, 0x96);
+			mdelay(100);
+			em28xx_write_reg(dev, 0x0b, 0x82);
+			mdelay(100);
+		}
+
+		kref_init(&dev->dev_next->ref);
+	}
+
 	kref_init(&dev->ref);
 
 	request_modules(dev);
@@ -3753,15 +3861,29 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 	if (!dev)
 		return;
 
+	if (dev->dev_next != NULL) {
+		dev->dev_next->disconnected = 1;
+		dev_info(&dev->intf->dev, "Disconnecting %s\n",
+			dev->dev_next->name);
+		flush_request_modules(dev->dev_next);
+	}
+
 	dev->disconnected = 1;
 
-	dev_err(&dev->intf->dev, "Disconnecting\n");
+	dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name);
 
 	flush_request_modules(dev);
 
 	em28xx_close_extension(dev);
 
+	if (dev->dev_next != NULL)
+		em28xx_release_resources(dev->dev_next);
 	em28xx_release_resources(dev);
+
+	if (dev->dev_next != NULL) {
+		kref_put(&dev->dev_next->ref, em28xx_free_device);
+		dev->dev_next = NULL;
+	}
 	kref_put(&dev->ref, em28xx_free_device);
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 1d0d8cc..ef38e56 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -638,10 +638,18 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 	    dev->chip_id == CHIP_ID_EM28174 ||
 	    dev->chip_id == CHIP_ID_EM28178) {
 		/* The Transport Stream Enable Register moved in em2874 */
-		rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
-					   start ?
-					       EM2874_TS1_CAPTURE_ENABLE : 0x00,
-					   EM2874_TS1_CAPTURE_ENABLE);
+		if (dev->ts == PRIMARY_TS)
+			rc = em28xx_write_reg_bits(dev,
+				EM2874_R5F_TS_ENABLE,
+				start ?
+				EM2874_TS1_CAPTURE_ENABLE : 0x00,
+				EM2874_TS1_CAPTURE_ENABLE);
+		else
+			rc = em28xx_write_reg_bits(dev,
+				EM2874_R5F_TS_ENABLE,
+				start ?
+				EM2874_TS2_CAPTURE_ENABLE : 0x00,
+				EM2874_TS2_CAPTURE_ENABLE);
 	} else {
 		/* FIXME: which is the best order? */
 		/* video registers are sampled by VREF */
@@ -1077,7 +1085,11 @@ int em28xx_register_extension(struct em28xx_ops *ops)
 	mutex_lock(&em28xx_devlist_mutex);
 	list_add_tail(&ops->next, &em28xx_extension_devlist);
 	list_for_each_entry(dev, &em28xx_devlist, devlist) {
-		ops->init(dev);
+		if (ops->init) {
+			ops->init(dev);
+			if (dev->dev_next != NULL)
+				ops->init(dev->dev_next);
+		}
 	}
 	mutex_unlock(&em28xx_devlist_mutex);
 	pr_info("em28xx: Registered (%s) extension\n", ops->name);
@@ -1091,7 +1103,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
 
 	mutex_lock(&em28xx_devlist_mutex);
 	list_for_each_entry(dev, &em28xx_devlist, devlist) {
-		ops->fini(dev);
+		if (ops->fini) {
+			if (dev->dev_next != NULL)
+				ops->fini(dev->dev_next);
+			ops->fini(dev);
+		}
 	}
 	list_del(&ops->next);
 	mutex_unlock(&em28xx_devlist_mutex);
@@ -1106,8 +1122,11 @@ void em28xx_init_extension(struct em28xx *dev)
 	mutex_lock(&em28xx_devlist_mutex);
 	list_add_tail(&dev->devlist, &em28xx_devlist);
 	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-		if (ops->init)
+		if (ops->init) {
 			ops->init(dev);
+			if (dev->dev_next != NULL)
+				ops->init(dev->dev_next);
+		}
 	}
 	mutex_unlock(&em28xx_devlist_mutex);
 }
@@ -1118,8 +1137,11 @@ void em28xx_close_extension(struct em28xx *dev)
 
 	mutex_lock(&em28xx_devlist_mutex);
 	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-		if (ops->fini)
+		if (ops->fini) {
+			if (dev->dev_next != NULL)
+				ops->fini(dev->dev_next);
 			ops->fini(dev);
+		}
 	}
 	list_del(&dev->devlist);
 	mutex_unlock(&em28xx_devlist_mutex);
@@ -1134,6 +1156,8 @@ int em28xx_suspend_extension(struct em28xx *dev)
 	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
 		if (ops->suspend)
 			ops->suspend(dev);
+		if (dev->dev_next != NULL)
+			ops->suspend(dev->dev_next);
 	}
 	mutex_unlock(&em28xx_devlist_mutex);
 	return 0;
@@ -1148,6 +1172,8 @@ int em28xx_resume_extension(struct em28xx *dev)
 	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
 		if (ops->resume)
 			ops->resume(dev);
+		if (dev->dev_next != NULL)
+			ops->resume(dev->dev_next);
 	}
 	mutex_unlock(&em28xx_devlist_mutex);
 	return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 8a81c94..9bc9576 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -199,7 +199,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
 	int rc;
 	struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
 	struct em28xx *dev = i2c_bus->dev;
-	struct usb_device *udev = interface_to_usbdev(dev->intf);
 	int dvb_max_packet_size, packet_multiplier, dvb_alt;
 
 	if (dev->dvb_xfer_bulk) {
@@ -218,7 +217,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
 		dvb_alt = dev->dvb_alt_isoc;
 	}
 
-	usb_set_interface(udev, dev->ifnum, dvb_alt);
 	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
 	if (rc < 0)
 		return rc;
@@ -1128,8 +1126,9 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
 
 static int em28xx_dvb_init(struct em28xx *dev)
 {
-	int result = 0;
+	int result = 0, dvb_alt = 0;
 	struct em28xx_dvb *dvb;
+	struct usb_device *udev;
 
 	if (dev->is_audio_only) {
 		/* Shouldn't initialize IR for this interface */
@@ -1914,7 +1913,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
 			si2168_config.ts_mode = SI2168_TS_SERIAL;
 			memset(&info, 0, sizeof(struct i2c_board_info));
 			strlcpy(info.type, "si2168", I2C_NAME_SIZE);
-			info.addr = 0x64;
+			if (dev->ts == PRIMARY_TS)
+				info.addr = 0x64;
+			else
+				info.addr = 0x67;
 			info.platform_data = &si2168_config;
 			request_module(info.type);
 			client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
@@ -1940,7 +1942,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
 #endif
 			memset(&info, 0, sizeof(struct i2c_board_info));
 			strlcpy(info.type, "si2157", I2C_NAME_SIZE);
-			info.addr = 0x60;
+			if (dev->ts == PRIMARY_TS)
+				info.addr = 0x60;
+			else
+				info.addr = 0x63;
 			info.platform_data = &si2157_config;
 			request_module(info.type);
 			client = i2c_new_device(adapter, &info);
@@ -1976,7 +1981,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
 			lgdt3306a_config.fe = &dvb->fe[0];
 			lgdt3306a_config.i2c_adapter = &adapter;
 			strlcpy(info.type, "lgdt3306a", sizeof(info.type));
-			info.addr = 0x59;
+			if (dev->ts == PRIMARY_TS)
+				info.addr = 0x59;
+			else
+				info.addr = 0x0e;
 			info.platform_data = &lgdt3306a_config;
 			request_module(info.type);
 			client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
@@ -2003,7 +2011,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
 #endif
 			memset(&info, 0, sizeof(struct i2c_board_info));
 			strlcpy(info.type, "si2157", sizeof(info.type));
-			info.addr = 0x60;
+			if (dev->ts == PRIMARY_TS)
+				info.addr = 0x60;
+			else
+				info.addr = 0x62;
 			info.platform_data = &si2157_config;
 			request_module(info.type);
 
@@ -2046,6 +2057,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	if (result < 0)
 		goto out_free;
 
+	if (dev->dvb_xfer_bulk) {
+		dvb_alt = 0;
+	} else { /* isoc */
+		dvb_alt = dev->dvb_alt_isoc;
+	}
+
+	udev = interface_to_usbdev(dev->intf);
+	usb_set_interface(udev, dev->ifnum, dvb_alt);
 	dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");
 
 	kref_get(&dev->ref);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 88084f2..c85292c 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -217,6 +217,9 @@
 /* max. number of button state polling addresses */
 #define EM28XX_NUM_BUTTON_ADDRESSES_MAX		5
 
+#define PRIMARY_TS	0
+#define SECONDARY_TS	1
+
 enum em28xx_mode {
 	EM28XX_SUSPEND,
 	EM28XX_ANALOG_MODE,
@@ -457,6 +460,7 @@ struct em28xx_board {
 	unsigned int mts_firmware:1;
 	unsigned int max_range_640_480:1;
 	unsigned int has_dvb:1;
+	unsigned int has_dual_ts:1;
 	unsigned int is_webcam:1;
 	unsigned int valid:1;
 	unsigned int has_ir_i2c:1;
@@ -621,6 +625,7 @@ struct em28xx {
 	unsigned int is_audio_only:1;
 	enum em28xx_int_audio_type int_audio_type;
 	enum em28xx_usb_audio_type usb_audio_type;
+	unsigned char name[32];
 
 	struct em28xx_board board;
 
@@ -682,6 +687,8 @@ struct em28xx {
 	u8 ifnum;		/* number of the assigned usb interface */
 	u8 analog_ep_isoc;	/* address of isoc endpoint for analog */
 	u8 analog_ep_bulk;	/* address of bulk endpoint for analog */
+	u8 dvb_ep_isoc_ts2;	/* address of isoc endpoint for DVB TS2*/
+	u8 dvb_ep_bulk_ts2;	/* address of bulk endpoint for DVB TS2*/
 	u8 dvb_ep_isoc;		/* address of isoc endpoint for DVB */
 	u8 dvb_ep_bulk;		/* address of bulk endpoint for DVB */
 	int alt;		/* alternate setting */
@@ -695,6 +702,8 @@ struct em28xx {
 	int dvb_alt_isoc;	/* alternate setting for DVB isoc transfers */
 	unsigned int dvb_max_pkt_size_isoc;	/* isoc max packet size of the
 						   selected DVB ep at dvb_alt */
+	unsigned int dvb_max_pkt_size_isoc_ts2;	/* isoc max packet size of the
+						   selected DVB ep at dvb_alt */
 	unsigned int dvb_xfer_bulk:1;		/* use bulk instead of isoc
 						   transfers for DVB          */
 	char urb_buf[URB_MAX_CTRL_SIZE];	/* urb control msg buffer */
@@ -726,6 +735,9 @@ struct em28xx {
 	struct media_entity input_ent[MAX_EM28XX_INPUT];
 	struct media_pad input_pad[MAX_EM28XX_INPUT];
 #endif
+
+	struct em28xx	*dev_next;
+	int ts;
 };
 
 #define kref_to_dev(d) container_of(d, struct em28xx, ref)
-- 
2.7.4

  reply	other threads:[~2018-01-05  0:05 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-05  0:04 [PATCH 0/9] Hauppauge em28xx/lgdt3306a soloHD/DualHD support Brad Love
2018-01-05  0:04 ` Brad Love [this message]
2018-01-05  0:21   ` [PATCH 1/9] em28xx: Hauppauge DualHD second tuner functionality Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 2/9] em28xx: Bulk transfer implementation fix Brad Love
2018-01-05  0:22   ` Michael Ira Krufky
2018-01-05 14:20     ` Devin Heitmueller
2018-01-05 15:21       ` Brad Love
2018-01-30 19:56       ` Brad Love
2018-01-30 12:07   ` Mauro Carvalho Chehab
2018-01-30 19:33     ` Brad Love
2018-02-01 22:04   ` [PATCH v2 " Brad Love
2018-01-05  0:04 ` [PATCH 3/9] em28xx: USB bulk packet size fix Brad Love
2018-01-05  0:23   ` Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 4/9] em28xx: Increase max em28xx boards to max dvb adapters Brad Love
2018-01-05  0:23   ` Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 5/9] em28xx: Add Hauppauge SoloHD/DualHD bulk models Brad Love
2018-01-05  0:24   ` Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 6/9] em28xx: Enable Hauppauge SoloHD rebranded 292e SE Brad Love
2018-01-05  0:24   ` Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 7/9] lgdt3306a: Set fe ops.release to NULL if probed Brad Love
2018-01-05  0:19   ` Michael Ira Krufky
2018-01-05  1:37     ` Brad Love
2018-01-09  5:17     ` Matthias Schwarzott
2018-01-09 13:00       ` Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 8/9] lgdt3306a: QAM streaming improvement Brad Love
2018-01-05  0:26   ` Michael Ira Krufky
2018-01-05  1:34     ` Brad Love
2018-01-05  1:30   ` [PATCH v2 " Brad Love
2018-01-05 11:57     ` Michael Ira Krufky
2018-01-05  0:04 ` [PATCH 9/9] lgdt3306a: Add QAM AUTO support Brad Love
2018-01-05  0:27   ` Michael Ira Krufky
2018-02-12 20:52   ` [PATCH v2 " Brad Love

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=1515110659-20145-2-git-send-email-brad@nextdimension.cc \
    --to=brad@nextdimension.cc \
    --cc=linux-media@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.