Hi,

Here's a patch against 2.4.18-pre3 that fixes the following bugs in the
USB stv680 driver:
        - fixed the problem with webcam crashing after two pictures
        - changed way pic is halved to improve quality
        - got rid of green line around frame
        - fixed brightness reset when changing size
        - adjusted gamma filters slightly.
It was written by Kevin Sisson.

thanks,

greg k-h


diff -Nru a/drivers/usb/stv680.c b/drivers/usb/stv680.c
--- a/drivers/usb/stv680.c      Fri Jan 11 11:26:02 2002
+++ b/drivers/usb/stv680.c      Fri Jan 11 11:26:02 2002
@@ -43,6 +43,13 @@
  *                        Took out sharpen function, ran code through
  *                        Lindent, and did other minor tweaks to get
  *                        things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap 
+always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@
        stv680->palette = STV_VIDEO_PALETTE;
        stv680->depth = 24;     /* rgb24 bits */
        swapRGB = 0;
-       PDEBUG (1, "STV(i): swapRGB is OFF");
-
+       if ((swapRGB_on == 0) && (swapRGB == 0))
+               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+       else if ((swapRGB_on == 1) && (swapRGB == 1))
+               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+       else if (swapRGB_on == 1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+       else if (swapRGB_on == -1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+       
        if (stv_set_video_mode (stv680) < 0) {
                PDEBUG (0, "STV(e): Could not set video mode in stv_init");
                return -1;
@@ -543,6 +558,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int 
*eof, void *data)
 {
@@ -559,7 +575,13 @@
        out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
        out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, 
stv680->vheight);
-       out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+       if (swapRGB_on == 0)
+               out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+       else if (swapRGB_on == 1)
+               out += sprintf (out, "swapRGB         : (forced) on\n");
+       else if (swapRGB_on == -1)
+               out += sprintf (out, "swapRGB         : (forced) off\n");
+
        out += sprintf (out, "Palette         : %i", stv680->palette);
 
        out += sprintf (out, "\n");
@@ -671,9 +693,7 @@
        if (stv680->brightness != p->brightness) {
                stv680->chgbright = 1;
                stv680->brightness = p->brightness;
-       } else {
-               stv680->chgbright = 0;
-       }
+       } 
 
        stv680->whiteness = p->whiteness;       /* greyscale */
        stv680->colour = p->colour;
@@ -888,7 +908,7 @@
 {
        int x, y, i;
        int w = stv680->cwidth;
-       int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+       int vw = stv680->cwidth, vh = stv680->cheight;
        unsigned int p = 0;
        int colour = 0, bayer = 0;
        unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@
                return;
        }
 
-       if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
                vw = 320;
                vh = 240;
-               vstep = 1;
        }
-       if ((stv680->vwidth == 352)) {
+       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
                vw = 352;
                vh = 288;
-               vstep = 1;
        }
-       if ((stv680->vwidth == 160)) {
-               vw = 160;
-               vh = 120;
-               vstep = 2;
-       }
-       if ((stv680->vwidth == 176)) {
-               vw = 176;
-               vh = 144;
-               vstep = 2;
-       }
-       memset (output, 0, 3 * vw * vh);        /* clear output matrix. Maybe not 
necessary. */
+
+       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
 
        for (y = 0; y < vh; y++) {
                for (x = 0; x < vw; x++) {
-
-                       switch (vstep) {
-                       case 1:
-                               if (x & 1)
-                                       p = *(raw + y * w + (x >> 1));
-                               else
-                                       p = *(raw + y * w + (x >> 1) + (w >> 1));
-                               break;
-
-                       case 2:
-                               if (x & 1)
-                                       p = *(raw + ((y * w) << 1) + x);
-                               else
-                                       p = *(raw + ((y * w) << 1) + x + (w >> 1));
-                               break;
-                       }
+                       if (x & 1)
+                               p = *(raw + y * w + (x >> 1));
+                       else
+                               p = *(raw + y * w + (x >> 1) + (w >> 1));
 
                        if (y & 1)
                                bayer = 2;
@@ -968,9 +965,10 @@
                                colour = 2;
                                break;
                        }
-                       i = (y * vw + x) * 3;   /* output already zeroed out with 
memset */
+                       i = (y * vw + x) * 3;   
                        *(output + i + colour) = (unsigned char) p;
                }               /* for x */
+
        }                       /* for y */
 
        /****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@
           (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
           White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float 
and 
           converted to unsigned char. Values are in stv680.h  */
+
        for (y = 0; y < vh; y++) {
                for (x = 0; x < vw; x++) {
                        i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@
                }               /* for x */
        }                       /* for y  - end demosaic  */
 
+       /* fix top and bottom row, left and right side */
+       i = vw * 3;
+       memcpy (output, (output + i), i);
+       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+       for (y = 0; y < vh; y++) {
+               i = y * vw * 3;
+               memcpy ((output + i), (output + i + 3), 3);
+               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+       }
+
+       /*  process all raw data, then trim to size if necessary */
+       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+               i = 0;
+               for (y = 0; y < vh; y++) {
+                       if (!(y & 1)) {
+                               for (x = 0; x < vw; x++) {
+                                       p = (y * vw + x) * 3;
+                                       if (!(x & 1)) {
+                                               *(output + i) = *(output + p);
+                                               *(output + i + 1) = *(output + p + 1);
+                                               *(output + i + 2) = *(output + p + 2);
+                                               i += 3;
+                                       }
+                               }  /* for x */
+                       }
+               }  /* for y */
+       }
+       /* reset to proper width */
+       if ((stv680->vwidth == 160)) {
+               vw = 160;
+               vh = 120;
+       }
+       if ((stv680->vwidth == 176)) {
+               vw = 176;
+               vh = 144;
+       }
+
        /* output is RGB; some programs want BGR  */
-       if (swapRGB == 1) {
+       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+       /* swapRGB_on=-1, never swap */
+       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
                for (y = 0; y < vh; y++) {
                        for (x = 0; x < vw; x++) {
                                i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@
                                return -EFAULT;
                        }
                        copy_from_user (&p, arg, sizeof (p));
-                       PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+                       PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", 
+p.palette);
 
                        if (stv680_set_pict (stv680, &p))
                                return -EINVAL;
@@ -1309,8 +1347,8 @@
                        if (vm.format != STV_VIDEO_PALETTE) {
                                PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != 
VIDEO_PALETTE (%i)",
                                        vm.format, STV_VIDEO_PALETTE);
-                               if (vm.format == 3) {
-                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is 
ON");
+                               if ((vm.format == 3) && (swapRGB_on == 0))  {
+                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is 
+(auto) ON");
                                        /* this may fix those apps (e.g., xawtv) that 
want BGR */
                                        swapRGB = 1;
                                }
@@ -1320,8 +1358,10 @@
                                PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > 
NUMFRAMES");
                                return -EINVAL;
                        }
-                       if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != 
FRAME_UNUSED");
+                       if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+                           || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) 
+error",
+                                       stv680->frame[vm.frame].grabstate);
                                return -EBUSY;
                        }
                        /* Is this according to the v4l spec??? */
diff -Nru a/drivers/usb/stv680.h b/drivers/usb/stv680.h
--- a/drivers/usb/stv680.h      Fri Jan 11 11:26:03 2002
+++ b/drivers/usb/stv680.h      Fri Jan 11 11:26:03 2002
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID  0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -146,77 +146,78 @@
        int nullpackets;
 };
 
-unsigned char red[256] = {
-       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-       245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+       220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-       0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-       24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-       58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-       92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-       114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-       133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-       148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-       162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-       175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-       187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-       197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-       207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-       217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-       225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-       235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-       243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-       250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255
-};
+       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+       245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-       0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-       31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-       74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-       116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-       145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-       168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-       187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-       205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-       222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-       236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-       250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255
-};
+       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+       249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+       255, 255, 255, 255 
+}; 

_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to