The patch number 10693 was added via Mauro Carvalho Chehab <mche...@redhat.com>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        Linux Media Mailing List <linux-me...@vger.kernel.org>

------

From: Mauro Carvalho Chehab  <mche...@redhat.com>
merge: http://www.linuxtv.org/hg/~hverkuil/v4l-dvb-usbvision


Signed-off-by: Mauro Carvalho Chehab <mche...@redhat.com>


---

 linux/drivers/media/video/usbvision/usbvision-core.c  |    2 
 linux/drivers/media/video/usbvision/usbvision-i2c.c   |  153 ++--------
 linux/drivers/media/video/usbvision/usbvision-video.c |   63 +---
 linux/drivers/media/video/usbvision/usbvision.h       |    8 
 linux/drivers/media/video/v4l2-common.c               |    9 
 linux/include/media/v4l2-common.h                     |    2 
 6 files changed, 89 insertions(+), 148 deletions(-)

diff -r f546b826a749 -r a169633cd720 
linux/drivers/media/video/usbvision/usbvision-core.c
--- a/linux/drivers/media/video/usbvision/usbvision-core.c      Thu Feb 26 
15:41:03 2009 -0300
+++ b/linux/drivers/media/video/usbvision/usbvision-core.c      Thu Feb 26 
16:31:15 2009 -0300
@@ -2654,7 +2654,7 @@ int usbvision_muxsel(struct usb_usbvisio
        }
        route.input = mode[channel];
        route.output = 0;
-       call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+       call_all(usbvision, video, s_routing, &route);
        usbvision_set_audio(usbvision, audio[channel]);
        return 0;
 }
diff -r f546b826a749 -r a169633cd720 
linux/drivers/media/video/usbvision/usbvision-i2c.c
--- a/linux/drivers/media/video/usbvision/usbvision-i2c.c       Thu Feb 26 
15:41:03 2009 -0300
+++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c       Thu Feb 26 
16:31:15 2009 -0300
@@ -206,72 +206,78 @@ static struct i2c_algorithm usbvision_al
 };
 
 
-/*
- * registering functions to load algorithms at runtime
- */
-static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
-{
-       PDEBUG(DBG_I2C, "I2C   debugging is enabled [i2c]");
-       PDEBUG(DBG_I2C, "ALGO   debugging is enabled [i2c]");
-
-       /* register new adapter to i2c module... */
-
-       adap->algo = &usbvision_algo;
-
-       adap->timeout = 100;    /* default values, should       */
-       adap->retries = 3;      /* be replaced by defines       */
-
-       i2c_add_adapter(adap);
-
-       PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name);
-
-       return 0;
-}
-
 /* ----------------------------------------------------------------------- */
 /* usbvision specific I2C functions                                        */
 /* ----------------------------------------------------------------------- */
 static struct i2c_adapter i2c_adap_template;
-static struct i2c_client i2c_client_template;
 
 int usbvision_i2c_register(struct usb_usbvision *usbvision)
 {
+       static unsigned short saa711x_addrs[] = {
+               0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
+               0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
+               I2C_CLIENT_END };
+
        memcpy(&usbvision->i2c_adap, &i2c_adap_template,
               sizeof(struct i2c_adapter));
-       memcpy(&usbvision->i2c_client, &i2c_client_template,
-              sizeof(struct i2c_client));
 
        sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
                " #%d", usbvision->vdev->num);
        PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
        usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
 
-       i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
-       i2c_set_clientdata(&usbvision->i2c_client, usbvision);
-
-       usbvision->i2c_client.adapter = &usbvision->i2c_adap;
+       i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
 
        if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, 
USBVISION_IIC_LRNACK) < 0) {
                printk(KERN_ERR "usbvision_register: can't write reg\n");
                return -EBUSY;
        }
 
-#ifdef CONFIG_MODULES
+       PDEBUG(DBG_I2C, "I2C   debugging is enabled [i2c]");
+       PDEBUG(DBG_I2C, "ALGO   debugging is enabled [i2c]");
+
+       /* register new adapter to i2c module... */
+
+       usbvision->i2c_adap.algo = &usbvision_algo;
+
+       usbvision->i2c_adap.timeout = 100;      /* default values, should       
*/
+       usbvision->i2c_adap.retries = 3;        /* be replaced by defines       
*/
+
+       i2c_add_adapter(&usbvision->i2c_adap);
+
+       PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name);
+
        /* Request the load of the i2c modules we need */
        switch (usbvision_device_data[usbvision->DevModel].Codec) {
        case CODEC_SAA7113:
-               request_module("saa7115");
+       case CODEC_SAA7111:
+               v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "saa7115",
+                               "saa7115_auto", saa711x_addrs);
                break;
-       case CODEC_SAA7111:
-               request_module("saa7115");
-               break;
        }
        if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
-               request_module("tuner");
-       }
-#endif
-
-       return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
+               struct v4l2_subdev *sd;
+               enum v4l2_i2c_tuner_type type;
+               struct tuner_setup tun_setup;
+
+               sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               /* depending on whether we found a demod or not, select
+                  the tuner type. */
+               type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+               sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
+                               "tuner", v4l2_i2c_tuner_addrs(type));
+
+               if (usbvision->tuner_type != -1) {
+                       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+                       tun_setup.type = usbvision->tuner_type;
+                       tun_setup.addr = v4l2_i2c_subdev_addr(sd);
+                       call_all(usbvision, tuner, s_type_addr, &tun_setup);
+               }
+       }
+
+       return 0;
 }
 
 int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
@@ -281,67 +287,6 @@ int usbvision_i2c_unregister(struct usb_
 
        PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name);
 
-       return 0;
-}
-
-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
-                     void *arg)
-{
-       i2c_clients_command(&usbvision->i2c_adap, cmd, arg);
-}
-
-static int attach_inform(struct i2c_client *client)
-{
-       struct usb_usbvision *usbvision;
-
-       usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
-
-       switch (client->addr << 1) {
-               case 0x42 << 1:
-               case 0x43 << 1:
-               case 0x4a << 1:
-               case 0x4b << 1:
-                       PDEBUG(DBG_I2C,"attach_inform: tda9887 detected.");
-                       break;
-               case 0x42:
-                       PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
-                       break;
-               case 0x4a:
-                       PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.");
-                       break;
-               case 0x48:
-                       PDEBUG(DBG_I2C,"attach_inform: saa7111 detected.");
-                       break;
-               case 0xa0:
-                       PDEBUG(DBG_I2C,"attach_inform: eeprom detected.");
-                       break;
-
-               default:
-                       {
-                               struct tuner_setup tun_setup;
-
-                               PDEBUG(DBG_I2C,"attach inform: detected I2C 
address %x", client->addr << 1);
-                               usbvision->tuner_addr = client->addr;
-
-                               if ((usbvision->have_tuner) && 
(usbvision->tuner_type != -1)) {
-                                       tun_setup.mode_mask = T_ANALOG_TV | 
T_RADIO;
-                                       tun_setup.type = usbvision->tuner_type;
-                                       tun_setup.addr = usbvision->tuner_addr;
-                                       call_i2c_clients(usbvision, 
TUNER_SET_TYPE_ADDR, &tun_setup);
-                               }
-                       }
-                       break;
-       }
-       return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-       struct usb_usbvision *usbvision;
-
-       usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
-
-       PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, 
client->name);
        return 0;
 }
 
@@ -517,14 +462,6 @@ static struct i2c_adapter i2c_adap_templ
 static struct i2c_adapter i2c_adap_template = {
        .owner = THIS_MODULE,
        .name              = "usbvision",
-       .id                = I2C_HW_B_BT848, /* FIXME */
-       .client_register   = attach_inform,
-       .client_unregister = detach_inform,
-       .class             = I2C_CLASS_TV_ANALOG,
-};
-
-static struct i2c_client i2c_client_template = {
-       .name           = "usbvision internal",
 };
 
 /*
diff -r f546b826a749 -r a169633cd720 
linux/drivers/media/video/usbvision/usbvision-video.c
--- a/linux/drivers/media/video/usbvision/usbvision-video.c     Thu Feb 26 
15:41:03 2009 -0300
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c     Thu Feb 26 
16:31:15 2009 -0300
@@ -212,7 +212,7 @@ static ssize_t show_hue(struct device *c
        ctrl.id = V4L2_CID_HUE;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
@@ -227,7 +227,7 @@ static ssize_t show_contrast(struct devi
        ctrl.id = V4L2_CID_CONTRAST;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
@@ -242,7 +242,7 @@ static ssize_t show_brightness(struct de
        ctrl.id = V4L2_CID_BRIGHTNESS;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
@@ -257,7 +257,7 @@ static ssize_t show_saturation(struct de
        ctrl.id = V4L2_CID_SATURATION;
        ctrl.value = 0;
        if(usbvision->user)
-               call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+               call_all(usbvision, core, g_ctrl, &ctrl);
        return sprintf(buf, "%d\n", ctrl.value);
 }
 static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
@@ -622,8 +622,7 @@ static int vidioc_s_std (struct file *fi
        usbvision->tvnormId=*id;
 
        mutex_lock(&usbvision->lock);
-       call_i2c_clients(usbvision, VIDIOC_S_STD,
-                        &usbvision->tvnormId);
+       call_all(usbvision, tuner, s_std, usbvision->tvnormId);
        mutex_unlock(&usbvision->lock);
        /* propagate the change to the decoder */
        usbvision_muxsel(usbvision, usbvision->ctl_input);
@@ -645,7 +644,7 @@ static int vidioc_g_tuner (struct file *
                strcpy(vt->name, "Television");
        }
        /* Let clients fill in the remainder of this struct */
-       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+       call_all(usbvision, tuner, g_tuner, vt);
 
        return 0;
 }
@@ -659,7 +658,7 @@ static int vidioc_s_tuner (struct file *
        if (!usbvision->have_tuner || vt->index)
                return -EINVAL;
        /* let clients handle this */
-       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+       call_all(usbvision, tuner, s_tuner, vt);
 
        return 0;
 }
@@ -690,7 +689,7 @@ static int vidioc_s_frequency (struct fi
                return -EINVAL;
 
        usbvision->freq = freq->frequency;
-       call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
+       call_all(usbvision, tuner, s_frequency, freq);
 
        return 0;
 }
@@ -728,7 +727,7 @@ static int vidioc_queryctrl (struct file
        memset(ctrl,0,sizeof(*ctrl));
        ctrl->id=id;
 
-       call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
+       call_all(usbvision, core, queryctrl, ctrl);
 
        if (!ctrl->type)
                return -EINVAL;
@@ -740,7 +739,7 @@ static int vidioc_g_ctrl (struct file *f
                                struct v4l2_control *ctrl)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+       call_all(usbvision, core, g_ctrl, ctrl);
 
        return 0;
 }
@@ -749,7 +748,7 @@ static int vidioc_s_ctrl (struct file *f
                                struct v4l2_control *ctrl)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+       call_all(usbvision, core, s_ctrl, ctrl);
 
        return 0;
 }
@@ -900,10 +899,9 @@ static int vidioc_streamon(struct file *
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        usbvision->streaming = Stream_On;
-       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+       call_all(usbvision, video, s_stream, 1);
 
        return 0;
 }
@@ -912,7 +910,6 @@ static int vidioc_streamoff(struct file 
                            void *priv, enum v4l2_buf_type type)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
-       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -920,7 +917,7 @@ static int vidioc_streamoff(struct file 
        if(usbvision->streaming == Stream_On) {
                usbvision_stream_interrupt(usbvision);
                /* Stop all video streamings */
-               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+               call_all(usbvision, video, s_stream, 0);
        }
        usbvision_empty_framequeues(usbvision);
 
@@ -1043,7 +1040,7 @@ static ssize_t usbvision_v4l2_read(struc
        if(usbvision->streaming != Stream_On) {
                /* no stream is running, make it running ! */
                usbvision->streaming = Stream_On;
-               call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+               call_all(usbvision, video, s_stream, 1);
        }
 
        /* Then, enqueue as many frames as possible
@@ -1214,7 +1211,7 @@ static int usbvision_radio_open(struct f
 
                // If so far no errors then we shall start the radio
                usbvision->radio = 1;
-               
call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
+               call_all(usbvision, tuner, s_radio);
                usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
                usbvision->user++;
        }
@@ -1427,7 +1424,7 @@ static struct video_device *usbvision_vd
        }
        *vdev = *vdev_template;
 //     vdev->minor   = -1;
-       vdev->parent  = &usb_dev->dev;
+       vdev->v4l2_dev = &usbvision->v4l2_dev;
        snprintf(vdev->name, sizeof(vdev->name), "%s", name);
        video_set_drvdata(vdev, usbvision);
        return vdev;
@@ -1548,33 +1545,30 @@ static struct usb_usbvision *usbvision_a
 {
        struct usb_usbvision *usbvision;
 
-       if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
-           NULL) {
-               goto err_exit;
-       }
+       usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL);
+       if (usbvision == NULL)
+               return NULL;
 
        usbvision->dev = dev;
+       if (v4l2_device_register(&dev->dev, &usbvision->v4l2_dev))
+               goto err_free;
 
        mutex_init(&usbvision->lock);   /* available */
 
        // prepare control urb for control messages during interrupts
        usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
-       if (usbvision->ctrlUrb == NULL) {
-               goto err_exit;
-       }
+       if (usbvision->ctrlUrb == NULL)
+               goto err_unreg;
        init_waitqueue_head(&usbvision->ctrlUrb_wq);
 
        usbvision_init_powerOffTimer(usbvision);
 
        return usbvision;
 
-err_exit:
-       if (usbvision && usbvision->ctrlUrb) {
-               usb_free_urb(usbvision->ctrlUrb);
-       }
-       if (usbvision) {
-               kfree(usbvision);
-       }
+err_unreg:
+       v4l2_device_unregister(&usbvision->v4l2_dev);
+err_free:
+       kfree(usbvision);
        return NULL;
 }
 
@@ -1604,6 +1598,7 @@ static void usbvision_release(struct usb
                usb_free_urb(usbvision->ctrlUrb);
        }
 
+       v4l2_device_unregister(&usbvision->v4l2_dev);
        kfree(usbvision);
 
        PDEBUG(DBG_PROBE, "success");
@@ -1738,8 +1733,6 @@ static int __devinit usbvision_probe(str
        if (usbvision->have_tuner) {
                usbvision->tuner_type = usbvision_device_data[model].TunerType;
        }
-
-       usbvision->tuner_addr = ADDR_UNSET;
 
        usbvision->DevModel = model;
        usbvision->remove_pending = 0;
diff -r f546b826a749 -r a169633cd720 
linux/drivers/media/video/usbvision/usbvision.h
--- a/linux/drivers/media/video/usbvision/usbvision.h   Thu Feb 26 15:41:03 
2009 -0300
+++ b/linux/drivers/media/video/usbvision/usbvision.h   Thu Feb 26 16:31:15 
2009 -0300
@@ -35,7 +35,7 @@
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <linux/videodev2.h>
 #include "compat.h"
@@ -358,13 +358,13 @@ extern struct usb_device_id usbvision_ta
 extern struct usb_device_id usbvision_table[];
 
 struct usb_usbvision {
+       struct v4l2_device v4l2_dev;
        struct video_device *vdev;                                      /* 
Video Device */
        struct video_device *rdev;                                      /* 
Radio Device */
        struct video_device *vbi;                                       /* VBI 
Device   */
 
        /* i2c Declaration Section*/
        struct i2c_adapter i2c_adap;
-       struct i2c_client i2c_client;
 
        struct urb *ctrlUrb;
        unsigned char ctrlUrbBuffer[8];
@@ -375,7 +375,6 @@ struct usb_usbvision {
        /* configuration part */
        int have_tuner;
        int tuner_type;
-       int tuner_addr;
        int bridgeType;                                                 // 
NT1003, NT1004, NT1005
        int radio;
        int video_inputs;                                               // # of 
inputs
@@ -465,6 +464,8 @@ struct usb_usbvision {
        int ComprBlockTypes[4];
 };
 
+#define call_all(usbvision, o, f, args...) \
+       v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args)
 
 /* --------------------------------------------------------------- */
 /* defined in usbvision-i2c.c                                      */
@@ -476,7 +477,6 @@ struct usb_usbvision {
 /* ----------------------------------------------------------------------- */
 int usbvision_i2c_register(struct usb_usbvision *usbvision);
 int usbvision_i2c_unregister(struct usb_usbvision *usbvision);
-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void 
*arg);
 
 /* defined in usbvision-core.c                                      */
 int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
diff -r f546b826a749 -r a169633cd720 linux/drivers/media/video/v4l2-common.c
--- a/linux/drivers/media/video/v4l2-common.c   Thu Feb 26 15:41:03 2009 -0300
+++ b/linux/drivers/media/video/v4l2-common.c   Thu Feb 26 16:31:15 2009 -0300
@@ -1080,6 +1080,15 @@ struct v4l2_subdev *v4l2_i2c_new_probed_
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
 
+/* Return i2c client address of v4l2_subdev. */
+unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return client ? client->addr : I2C_CLIENT_END;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
+
 /* Return a list of I2C tuner addresses to probe. Use only if the tuner
    addresses are unknown. */
 const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
diff -r f546b826a749 -r a169633cd720 linux/include/media/v4l2-common.h
--- a/linux/include/media/v4l2-common.h Thu Feb 26 15:41:03 2009 -0300
+++ b/linux/include/media/v4l2-common.h Thu Feb 26 16:31:15 2009 -0300
@@ -154,6 +154,8 @@ struct v4l2_subdev *v4l2_i2c_new_probed_
 /* Initialize an v4l2_subdev with data from an i2c_client struct */
 void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops);
+/* Return i2c client address of v4l2_subdev. */
+unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd);
 
 enum v4l2_i2c_tuner_type {
        ADDRS_RADIO,    /* Radio tuner addresses */


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/a169633cd720d09482b652e67322ab88cce1706b

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to