From 7ebc8760b38bb00c35fcf43dad438c2adcd7c328 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 11 Jul 2010 10:54:51 +0100 Subject: [PATCH 335/524] Staging: easycap: Upsample microphone audio Upsampling from 8000 Hz mono to 32000 Hz stereo improves audio/video synchronization when userspace programs adopt default buffering. This is an experimental feature. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 2 +- drivers/staging/easycap/easycap_ioctl.c | 35 ++++++++++++++ drivers/staging/easycap/easycap_low.c | 66 ++++++++++---------------- drivers/staging/easycap/easycap_main.c | 15 ++++++- drivers/staging/easycap/easycap_sound.c | 78 ++++++++++++++++++++++++++++-- 5 files changed, 147 insertions(+), 49 deletions(-) diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index ce8b16f..ad836d2 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -135,7 +135,7 @@ #define USB_EASYCAP_VENDOR_ID 0x05e1 #define USB_EASYCAP_PRODUCT_ID 0x0408 -#define EASYCAP_DRIVER_VERSION "0.8.2" +#define EASYCAP_DRIVER_VERSION "0.8.21" #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60" #define USB_SKEL_MINOR_BASE 192 diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 5853bba..7227d73 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -1985,10 +1985,17 @@ case SNDCTL_DSP_GETCAPS: { int caps; JOT(8, "SNDCTL_DSP_GETCAPS\n"); +#if defined(UPSAMPLE) + if (true == peasycap->microphone) + caps = 0x04400000; + else + caps = 0x04400000; +#else if (true == peasycap->microphone) caps = 0x02400000; else caps = 0x04400000; +#endif /*UPSAMPLE*/ if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) return -EFAULT; @@ -1998,10 +2005,17 @@ case SNDCTL_DSP_GETFMTS: { int incoming; JOT(8, "SNDCTL_DSP_GETFMTS\n"); +#if defined(UPSAMPLE) + if (true == peasycap->microphone) + incoming = AFMT_S16_LE; + else + incoming = AFMT_S16_LE; +#else if (true == peasycap->microphone) incoming = AFMT_S16_LE; else incoming = AFMT_S16_LE; +#endif /*UPSAMPLE*/ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) return -EFAULT; @@ -2014,10 +2028,17 @@ case SNDCTL_DSP_SETFMT: { return -EFAULT; JOT(8, "........... %i=incoming\n", incoming); +#if defined(UPSAMPLE) if (true == peasycap->microphone) outgoing = AFMT_S16_LE; else outgoing = AFMT_S16_LE; +#else + if (true == peasycap->microphone) + outgoing = AFMT_S16_LE; + else + outgoing = AFMT_S16_LE; +#endif /*UPSAMPLE*/ if (incoming != outgoing) { JOT(8, "........... %i=outgoing\n", outgoing); @@ -2037,10 +2058,17 @@ case SNDCTL_DSP_STEREO: { return -EFAULT; JOT(8, "........... %i=incoming\n", incoming); +#if defined(UPSAMPLE) + if (true == peasycap->microphone) + incoming = 1; + else + incoming = 1; +#else if (true == peasycap->microphone) incoming = 0; else incoming = 1; +#endif /*UPSAMPLE*/ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) return -EFAULT; @@ -2053,10 +2081,17 @@ case SNDCTL_DSP_SPEED: { return -EFAULT; JOT(8, "........... %i=incoming\n", incoming); +#if defined(UPSAMPLE) + if (true == peasycap->microphone) + incoming = 32000; + else + incoming = 48000; +#else if (true == peasycap->microphone) incoming = 8000; else incoming = 48000; +#endif /*UPSAMPLE*/ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) return -EFAULT; diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index e7c189a..ad1fc4c 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -827,7 +827,7 @@ static __u16 index = 0x0301; static unsigned char buffer[1]; static __u16 length = 1; -int rc; +int rc, id1, id2; if (NULL == peasycap) return -EFAULT; @@ -883,46 +883,30 @@ SET(pusb_device, 0x0500, 0x008C); SET(pusb_device, 0x0506, 0x0001); SET(pusb_device, 0x0507, 0x0000); -if (false == peasycap->microphone) { - /*-------------------------------------------------------------------*/ - /* - * SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0dB. - */ - /*-------------------------------------------------------------------*/ - write_vt(pusb_device, 0x0002, 0x8000); - write_vt(pusb_device, 0x001C, 0x8000); - - write_vt(pusb_device, 0x000E, 0x0000); - write_vt(pusb_device, 0x0010, 0x0000); - write_vt(pusb_device, 0x0012, 0x8000); - write_vt(pusb_device, 0x0016, 0x0000); - - write_vt(pusb_device, 0x001A, 0x0404); - write_vt(pusb_device, 0x0002, 0x0000); - write_vt(pusb_device, 0x001C, 0x0000); -} else { - /*-------------------------------------------------------------------*/ - /* - * SELECT AUDIO SOURCE "MIC" AND SET DEFAULT GAIN TO 0 dB. - * - * REGISTER 0x000E CAN BE SET TO PROVIDE UP TO 34.5 dB ATTENTUATION, - * BUT THIS HAS NOT PROVED NECESSARY FOR THE FEW SIGNAL SOURCES - * TESTED HITHERTO. - */ - /*-------------------------------------------------------------------*/ - write_vt(pusb_device, 0x0006, 0x8000); - write_vt(pusb_device, 0x001C, 0x8000); - - write_vt(pusb_device, 0x000E, 0x0008); - - write_vt(pusb_device, 0x0010, 0x0000); - write_vt(pusb_device, 0x0012, 0x8000); - write_vt(pusb_device, 0x0016, 0x0000); - - write_vt(pusb_device, 0x001A, 0x0000); - write_vt(pusb_device, 0x0006, 0x0000); - write_vt(pusb_device, 0x001C, 0x0000); -} +id1 = read_vt(pusb_device, 0x007C); +id2 = read_vt(pusb_device, 0x007E); +SAY("0x%04X:0x%04X is audio vendor id\n", id1, id2); + +/*---------------------------------------------------------------------------*/ +/* +* SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0 dB. +* +* THESE COMMANDS SEEM TO BE ACCEPTED (THOUGH POSSIBLY IGNORED) EVEN WHEN +* THERE IS NO SEPARATE AUDIO CHIP PRESENT. +*/ +/*---------------------------------------------------------------------------*/ + +write_vt(pusb_device, 0x0002, 0x8000); +write_vt(pusb_device, 0x001C, 0x8000); + +write_vt(pusb_device, 0x000E, 0x0000); +write_vt(pusb_device, 0x0010, 0x0000); +write_vt(pusb_device, 0x0012, 0x8000); +write_vt(pusb_device, 0x0016, 0x0000); + +write_vt(pusb_device, 0x001A, 0x0404); +write_vt(pusb_device, 0x0002, 0x0000); +write_vt(pusb_device, 0x001C, 0x0000); check_vt(pusb_device); diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index b817c97..f7a65af 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -2490,6 +2490,10 @@ if (peasycap->video_idle) { SAY("EMSGSIZE\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); + break; + } default: { SAY("0x%08X\n", rc); break; @@ -2571,6 +2575,9 @@ if (purb->status) { case -ECONNRESET: { SAY("-ECONNRESET\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } default: { SAY("unknown error code 0x%08X\n", purb->status); break; } @@ -2630,6 +2637,9 @@ if (purb->status) { case -ECONNRESET: { strcpy(&errbuf[0], "-ECONNRESET"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } case -ESHUTDOWN: { strcpy(&errbuf[0], "-ESHUTDOWN"); break; } @@ -2949,6 +2959,9 @@ if (peasycap->video_isoc_streaming) { case -EMSGSIZE: { SAY("EMSGSIZE\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } default: { SAY("0x%08X\n", rc); break; } @@ -3861,7 +3874,7 @@ case 2: { peasycap->ilk |= 0x02; SAY("hardware is FOUR-CVBS\n"); peasycap->microphone = true; - peasycap->audio_pages_per_fragment = 2; + peasycap->audio_pages_per_fragment = 4; } else if (256 == peasycap->audio_isoc_maxframesize) { peasycap->ilk &= ~0x02; SAY("hardware is CVBS+S-VIDEO\n"); diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c index 2bf32e1..37eaf42 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/easycap/easycap_sound.c @@ -50,6 +50,10 @@ char errbuf[16]; __u8 *p1, *p2; __s16 s16; int i, j, more, much, leap, rc; +#if defined(UPSAMPLE) +int k; +__s16 oldaudio, newaudio, delta; +#endif /*UPSAMPLE*/ JOT(16, "\n"); @@ -99,6 +103,9 @@ if (peasycap->audio_idle) { case -EMSGSIZE: { SAY("EMSGSIZE\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } default: { SAY("0x%08X\n", rc); break; } @@ -172,6 +179,9 @@ if (purb->status) { case -ECONNRESET: { SAY("-ECONNRESET\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } default: { SAY("unknown error code 0x%08X\n", purb->status); break; } @@ -226,6 +236,10 @@ if (purb->status) { * PROCEED HERE WHEN NO ERROR */ /*---------------------------------------------------------------------------*/ +#if defined(UPSAMPLE) +oldaudio = peasycap->oldaudio; +#endif /*UPSAMPLE*/ + for (i = 0; i < purb->number_of_packets; i++) { switch (purb->iso_frame_desc[i].status) { case 0: { @@ -276,6 +290,9 @@ for (i = 0; i < purb->number_of_packets; i++) { case -ECONNRESET: { strcpy(&errbuf[0], "-ECONNRESET"); break; } + case -ENOSPC: { + strcpy(&errbuf[0], "-ENOSPC"); break; + } case -ESHUTDOWN: { strcpy(&errbuf[0], "-ESHUTDOWN"); break; } @@ -318,7 +335,7 @@ for (i = 0; i < purb->number_of_packets; i++) { /*---------------------------------------------------------------------------*/ /* * COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER, - * CONVERTING 8-BIT SAMPLES TO 16-BIT SIGNED LITTLE-ENDED SAMPLES IF NECESSARY + * CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY */ /*---------------------------------------------------------------------------*/ while (more) { @@ -386,8 +403,6 @@ for (i = 0; i < purb->number_of_packets; i++) { much = PAGE_SIZE - (int)(paudio_buffer->pto -\ paudio_buffer->pgo); - if (much % 2) - JOT(8, "MISTAKE? much is odd\n"); if (false == peasycap->microphone) { if (much > more) @@ -397,17 +412,57 @@ for (i = 0; i < purb->number_of_packets; i++) { p1 += much; more -= much; } else { +#if defined(UPSAMPLE) + if (much % 16) + JOT(8, "MISTAKE? much" \ + " is not divisible by 16\n"); + if (much > (16 * \ + more)) + much = 16 * \ + more; + p2 = (__u8 *)paudio_buffer->pto; + + for (j = 0; j < (much/16); j++) { + newaudio = ((int) *p1) - 128; + newaudio = 128 * \ + newaudio; + + delta = (newaudio - oldaudio) \ + / 4; + s16 = oldaudio + delta; + + for (k = 0; k < 4; k++) { + *p2 = (0x00FF & s16); + *(p2 + 1) = (0xFF00 & \ + s16) >> 8; + p2 += 2; + *p2 = (0x00FF & s16); + *(p2 + 1) = (0xFF00 & \ + s16) >> 8; + p2 += 2; + + s16 += delta; + } + p1++; + more--; + oldaudio = s16; + } +#else if (much > (2 * more)) much = 2 * more; p2 = (__u8 *)paudio_buffer->pto; for (j = 0; j < (much / 2); j++) { s16 = ((int) *p1) - 128; - *p2 = (0xFF00 & s16) >> 8; - *(p2 + 1) = (0x00FF & s16); + s16 = 128 * \ + s16; + *p2 = (0x00FF & s16); + *(p2 + 1) = (0xFF00 & s16) >> \ + 8; p1++; p2 += 2; more--; } +#endif /*UPSAMPLE*/ } (paudio_buffer->pto) += much; } @@ -417,6 +472,11 @@ for (i = 0; i < purb->number_of_packets; i++) { "%i=purb->iso_frame_desc[i].status\n", \ purb->iso_frame_desc[i].status); } + +#if defined(UPSAMPLE) +peasycap->oldaudio = oldaudio; +#endif /*UPSAMPLE*/ + } /*---------------------------------------------------------------------------*/ /* @@ -453,6 +513,9 @@ if (peasycap->audio_isoc_streaming) { case -EMSGSIZE: { SAY("EMSGSIZE\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } default: { SAY("0x%08X\n", rc); break; } @@ -764,7 +827,7 @@ if (peasycap->audio_sample) { mean = peasycap->audio_niveau; sdr = signed_div(mean, peasycap->audio_sample); - JOT(12, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \ + JOT(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \ sdr.quotient, above, peasycap->audio_sample); sdr = signed_div(above, 32768); @@ -902,6 +965,9 @@ if (!peasycap->audio_isoc_streaming) { case -EMSGSIZE: { SAY("EMSGSIZE\n"); break; } + case -ENOSPC: { + SAY("ENOSPC\n"); break; + } default: { SAY("unknown error code %i\n",\ rc); break; -- 1.7.1