linux/drivers/staging/easycap/easycap_sound_oss.c
<<
>>
Prefs
   1/******************************************************************************
   2*                                                                             *
   3*  easycap_sound.c                                                            *
   4*                                                                             *
   5*  Audio driver for EasyCAP USB2.0 Video Capture Device DC60                  *
   6*                                                                             *
   7*                                                                             *
   8******************************************************************************/
   9/*
  10 *
  11 *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
  12 *
  13 *
  14 *  This is free software; you can redistribute it and/or modify
  15 *  it under the terms of the GNU General Public License as published by
  16 *  the Free Software Foundation; either version 2 of the License, or
  17 *  (at your option) any later version.
  18 *
  19 *  The software is distributed in the hope that it will be useful,
  20 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 *  GNU General Public License for more details.
  23 *
  24 *  You should have received a copy of the GNU General Public License
  25 *  along with this software; if not, write to the Free Software
  26 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  27 *
  28*/
  29/*****************************************************************************/
  30
  31#include "easycap.h"
  32
  33/*****************************************************************************/
  34/****************************                       **************************/
  35/****************************   Open Sound System   **************************/
  36/****************************                       **************************/
  37/*****************************************************************************/
  38/*--------------------------------------------------------------------------*/
  39/*
  40 *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
  41 */
  42/*--------------------------------------------------------------------------*/
  43/*****************************************************************************/
  44/*---------------------------------------------------------------------------*/
  45/*
  46 *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
  47 *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
  48 *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
  49 */
  50/*---------------------------------------------------------------------------*/
  51void
  52easyoss_complete(struct urb *purb)
  53{
  54        struct easycap *peasycap;
  55        struct data_buffer *paudio_buffer;
  56        u8 *p1, *p2;
  57        s16 tmp;
  58        int i, j, more, much, leap, rc;
  59#ifdef UPSAMPLE
  60        int k;
  61        s16 oldaudio, newaudio, delta;
  62#endif /*UPSAMPLE*/
  63
  64        JOT(16, "\n");
  65
  66        if (!purb) {
  67                SAY("ERROR: purb is NULL\n");
  68                return;
  69        }
  70        peasycap = purb->context;
  71        if (!peasycap) {
  72                SAY("ERROR: peasycap is NULL\n");
  73                return;
  74        }
  75        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
  76                SAY("ERROR: bad peasycap\n");
  77                return;
  78        }
  79        much = 0;
  80        if (peasycap->audio_idle) {
  81                JOM(16, "%i=audio_idle  %i=audio_isoc_streaming\n",
  82                    peasycap->audio_idle, peasycap->audio_isoc_streaming);
  83                if (peasycap->audio_isoc_streaming) {
  84                        rc = usb_submit_urb(purb, GFP_ATOMIC);
  85                        if (rc) {
  86                                if (-ENODEV != rc && -ENOENT != rc) {
  87                                        SAM("ERROR: while %i=audio_idle, "
  88                                            "usb_submit_urb() failed with rc: -%s: %d\n",
  89                                            peasycap->audio_idle,
  90                                            strerror(rc), rc);
  91                                }
  92                        }
  93                }
  94                return;
  95        }
  96/*---------------------------------------------------------------------------*/
  97        if (purb->status) {
  98                if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
  99                        JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
 100                        return;
 101                }
 102                SAM("ERROR: non-zero urb status: -%s: %d\n",
 103                    strerror(purb->status), purb->status);
 104                goto resubmit;
 105        }
 106/*---------------------------------------------------------------------------*/
 107/*
 108 *  PROCEED HERE WHEN NO ERROR
 109 */
 110/*---------------------------------------------------------------------------*/
 111#ifdef UPSAMPLE
 112        oldaudio = peasycap->oldaudio;
 113#endif /*UPSAMPLE*/
 114
 115        for (i = 0;  i < purb->number_of_packets; i++) {
 116                if (!purb->iso_frame_desc[i].status) {
 117
 118                        SAM("-%s\n", strerror(purb->iso_frame_desc[i].status));
 119
 120                        more = purb->iso_frame_desc[i].actual_length;
 121
 122                        if (!more)
 123                                peasycap->audio_mt++;
 124                        else {
 125                                if (peasycap->audio_mt) {
 126                                        JOM(12, "%4i empty audio urb frames\n",
 127                                            peasycap->audio_mt);
 128                                        peasycap->audio_mt = 0;
 129                                }
 130
 131                                p1 = (u8 *)(purb->transfer_buffer + purb->iso_frame_desc[i].offset);
 132
 133                                leap = 0;
 134                                p1 += leap;
 135                                more -= leap;
 136                                /*
 137                                 *  COPY more BYTES FROM ISOC BUFFER
 138                                 *  TO AUDIO BUFFER, CONVERTING
 139                                 *  8-BIT MONO TO 16-BIT SIGNED
 140                                 *  LITTLE-ENDIAN SAMPLES IF NECESSARY
 141                                 */
 142                                while (more) {
 143                                        if (0 > more) {
 144                                                SAM("MISTAKE: more is negative\n");
 145                                                return;
 146                                        }
 147                                        if (peasycap->audio_buffer_page_many <= peasycap->audio_fill) {
 148                                                SAM("ERROR: bad peasycap->audio_fill\n");
 149                                                return;
 150                                        }
 151
 152                                        paudio_buffer = &peasycap->audio_buffer[peasycap->audio_fill];
 153                                        if (PAGE_SIZE < (paudio_buffer->pto - paudio_buffer->pgo)) {
 154                                                SAM("ERROR: bad paudio_buffer->pto\n");
 155                                                return;
 156                                        }
 157                                        if (PAGE_SIZE == (paudio_buffer->pto - paudio_buffer->pgo)) {
 158
 159                                                paudio_buffer->pto = paudio_buffer->pgo;
 160                                                (peasycap->audio_fill)++;
 161                                                if (peasycap->audio_buffer_page_many <= peasycap->audio_fill)
 162                                                        peasycap->audio_fill = 0;
 163
 164                                                JOM(8, "bumped peasycap->"
 165                                                    "audio_fill to %i\n",
 166                                                    peasycap->audio_fill);
 167
 168                                                paudio_buffer = &peasycap->audio_buffer[peasycap->audio_fill];
 169                                                paudio_buffer->pto = paudio_buffer->pgo;
 170
 171                                                if (!(peasycap->audio_fill % peasycap->audio_pages_per_fragment)) {
 172                                                        JOM(12, "wakeup call on wq_audio, %i=frag reading  %i=fragment fill\n",
 173                                                            (peasycap->audio_read / peasycap->audio_pages_per_fragment),
 174                                                            (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 175                                                        wake_up_interruptible(&(peasycap->wq_audio));
 176                                                }
 177                                        }
 178
 179                                        much = PAGE_SIZE - (int)(paudio_buffer->pto - paudio_buffer->pgo);
 180
 181                                        if (!peasycap->microphone) {
 182                                                if (much > more)
 183                                                        much = more;
 184
 185                                                memcpy(paudio_buffer->pto, p1, much);
 186                                                p1 += much;
 187                                                more -= much;
 188                                        } else {
 189#ifdef UPSAMPLE
 190                                                if (much % 16)
 191                                                        JOM(8, "MISTAKE? much"
 192                                                            " is not divisible by 16\n");
 193                                                if (much > (16 * more))
 194                                                        much = 16 * more;
 195                                                p2 = (u8 *)paudio_buffer->pto;
 196
 197                                                for (j = 0;  j < (much/16);  j++) {
 198                                                        newaudio =  ((int) *p1) - 128;
 199                                                        newaudio = 128 * newaudio;
 200
 201                                                        delta = (newaudio - oldaudio) / 4;
 202                                                        tmp = oldaudio + delta;
 203
 204                                                        for (k = 0;  k < 4;  k++) {
 205                                                                *p2 = (0x00FF & tmp);
 206                                                                *(p2 + 1) = (0xFF00 & tmp) >> 8;
 207                                                                p2 += 2;
 208                                                                *p2 = (0x00FF & tmp);
 209                                                                *(p2 + 1) = (0xFF00 & tmp) >> 8;
 210                                                                p2 += 2;
 211
 212                                                                tmp += delta;
 213                                                        }
 214                                                        p1++;
 215                                                        more--;
 216                                                        oldaudio = tmp;
 217                                                }
 218#else /*!UPSAMPLE*/
 219                                                if (much > (2 * more))
 220                                                        much = 2 * more;
 221                                                p2 = (u8 *)paudio_buffer->pto;
 222
 223                                                for (j = 0;  j < (much / 2);  j++) {
 224                                                        tmp =  ((int) *p1) - 128;
 225                                                        tmp = 128 * tmp;
 226                                                        *p2 = (0x00FF & tmp);
 227                                                        *(p2 + 1) = (0xFF00 & tmp) >> 8;
 228                                                        p1++;
 229                                                        p2 += 2;
 230                                                        more--;
 231                                                }
 232#endif /*UPSAMPLE*/
 233                                        }
 234                                        (paudio_buffer->pto) += much;
 235                                }
 236                        }
 237                } else {
 238                        JOM(12, "discarding audio samples because "
 239                            "%i=purb->iso_frame_desc[i].status\n",
 240                            purb->iso_frame_desc[i].status);
 241                }
 242
 243#ifdef UPSAMPLE
 244                peasycap->oldaudio = oldaudio;
 245#endif /*UPSAMPLE*/
 246
 247        }
 248/*---------------------------------------------------------------------------*/
 249/*
 250 *  RESUBMIT THIS URB
 251 */
 252/*---------------------------------------------------------------------------*/
 253resubmit:
 254        if (peasycap->audio_isoc_streaming) {
 255                rc = usb_submit_urb(purb, GFP_ATOMIC);
 256                if (rc) {
 257                        if (-ENODEV != rc && -ENOENT != rc) {
 258                                SAM("ERROR: while %i=audio_idle, "
 259                                    "usb_submit_urb() failed "
 260                                    "with rc: -%s: %d\n", peasycap->audio_idle,
 261                                    strerror(rc), rc);
 262                        }
 263                }
 264        }
 265        return;
 266}
 267/*****************************************************************************/
 268/*---------------------------------------------------------------------------*/
 269/*
 270 *  THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
 271 *  STREAM FROM /dev/easyoss1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
 272 *  HAVE AN IOCTL INTERFACE.
 273 */
 274/*---------------------------------------------------------------------------*/
 275static int easyoss_open(struct inode *inode, struct file *file)
 276{
 277        struct usb_interface *pusb_interface;
 278        struct easycap *peasycap;
 279        int subminor;
 280        struct v4l2_device *pv4l2_device;
 281
 282        JOT(4, "begins\n");
 283
 284        subminor = iminor(inode);
 285
 286        pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
 287        if (!pusb_interface) {
 288                SAY("ERROR: pusb_interface is NULL\n");
 289                SAY("ending unsuccessfully\n");
 290                return -1;
 291        }
 292        peasycap = usb_get_intfdata(pusb_interface);
 293        if (!peasycap) {
 294                SAY("ERROR: peasycap is NULL\n");
 295                SAY("ending unsuccessfully\n");
 296                return -1;
 297        }
 298/*---------------------------------------------------------------------------*/
 299/*
 300 *  SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
 301 *  BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
 302 *  REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
 303 *  TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
 304*/
 305/*---------------------------------------------------------------------------*/
 306        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 307                pv4l2_device = usb_get_intfdata(pusb_interface);
 308                if (!pv4l2_device) {
 309                        SAY("ERROR: pv4l2_device is NULL\n");
 310                        return -EFAULT;
 311                }
 312                peasycap = container_of(pv4l2_device,
 313                                struct easycap, v4l2_device);
 314        }
 315/*---------------------------------------------------------------------------*/
 316        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 317                SAY("ERROR: bad peasycap: %p\n", peasycap);
 318                return -EFAULT;
 319        }
 320/*---------------------------------------------------------------------------*/
 321
 322        file->private_data = peasycap;
 323
 324        if (0 != easycap_sound_setup(peasycap)) {
 325                ;
 326                ;
 327        }
 328        return 0;
 329}
 330/*****************************************************************************/
 331static int easyoss_release(struct inode *inode, struct file *file)
 332{
 333        struct easycap *peasycap;
 334
 335        JOT(4, "begins\n");
 336
 337        peasycap = file->private_data;
 338        if (!peasycap) {
 339                SAY("ERROR:  peasycap is NULL.\n");
 340                return -EFAULT;
 341        }
 342        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 343                SAY("ERROR: bad peasycap: %p\n", peasycap);
 344                return -EFAULT;
 345        }
 346        if (0 != kill_audio_urbs(peasycap)) {
 347                SAM("ERROR: kill_audio_urbs() failed\n");
 348                return -EFAULT;
 349        }
 350        JOM(4, "ending successfully\n");
 351        return 0;
 352}
 353/*****************************************************************************/
 354static ssize_t easyoss_read(struct file *file, char __user *puserspacebuffer,
 355                            size_t kount, loff_t *poff)
 356{
 357        struct timeval timeval;
 358        long long int above, below, mean;
 359        struct signed_div_result sdr;
 360        unsigned char *p0;
 361        long int kount1, more, rc, l0, lm;
 362        int fragment, kd;
 363        struct easycap *peasycap;
 364        struct data_buffer *pdata_buffer;
 365        size_t szret;
 366
 367/*---------------------------------------------------------------------------*/
 368/*
 369 *  DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
 370 *
 371 ******************************************************************************
 372 *****  N.B.  IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
 373 *****        THIS CONDITION SIGNIFIES END-OF-FILE.                      ******
 374 ******************************************************************************
 375 */
 376/*---------------------------------------------------------------------------*/
 377
 378        JOT(8, "%5zd=kount  %5lld=*poff\n", kount, *poff);
 379
 380        if (!file) {
 381                SAY("ERROR:  file is NULL\n");
 382                return -ERESTARTSYS;
 383        }
 384        peasycap = file->private_data;
 385        if (!peasycap) {
 386                SAY("ERROR in easyoss_read(): peasycap is NULL\n");
 387                return -EFAULT;
 388        }
 389        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 390                SAY("ERROR: bad peasycap: %p\n", peasycap);
 391                return -EFAULT;
 392        }
 393        if (!peasycap->pusb_device) {
 394                SAY("ERROR: peasycap->pusb_device is NULL\n");
 395                return -EFAULT;
 396        }
 397        kd = isdongle(peasycap);
 398        if (0 <= kd && DONGLE_MANY > kd) {
 399                if (mutex_lock_interruptible(&(easycapdc60_dongle[kd].mutex_audio))) {
 400                        SAY("ERROR: "
 401                            "cannot lock dongle[%i].mutex_audio\n", kd);
 402                        return -ERESTARTSYS;
 403                }
 404                JOM(4, "locked dongle[%i].mutex_audio\n", kd);
 405                /*
 406                 *  MEANWHILE, easycap_usb_disconnect()
 407                 *  MAY HAVE FREED POINTER peasycap,
 408                 *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
 409                 *  IF NECESSARY, BAIL OUT.
 410                 */
 411                if (kd != isdongle(peasycap))
 412                        return -ERESTARTSYS;
 413                if (!file) {
 414                        SAY("ERROR:  file is NULL\n");
 415                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 416                        return -ERESTARTSYS;
 417                }
 418                peasycap = file->private_data;
 419                if (!peasycap) {
 420                        SAY("ERROR:  peasycap is NULL\n");
 421                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 422                        return -ERESTARTSYS;
 423                }
 424                if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 425                        SAY("ERROR: bad peasycap: %p\n", peasycap);
 426                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 427                        return -ERESTARTSYS;
 428                }
 429                if (!peasycap->pusb_device) {
 430                        SAM("ERROR: peasycap->pusb_device is NULL\n");
 431                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 432                        return -ERESTARTSYS;
 433                }
 434        } else {
 435                /*
 436                 *  IF easycap_usb_disconnect()
 437                 *  HAS ALREADY FREED POINTER peasycap BEFORE THE
 438                 *  ATTEMPT TO ACQUIRE THE SEMAPHORE,
 439                 *  isdongle() WILL HAVE FAILED.  BAIL OUT.
 440                 */
 441                return -ERESTARTSYS;
 442        }
 443/*---------------------------------------------------------------------------*/
 444        JOT(16, "%sBLOCKING kount=%zd, *poff=%lld\n",
 445                (file->f_flags & O_NONBLOCK) ? "NON" : "", kount, *poff);
 446
 447        if ((0 > peasycap->audio_read) ||
 448            (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
 449                SAM("ERROR: peasycap->audio_read out of range\n");
 450                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 451                return -EFAULT;
 452        }
 453        pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
 454        if (!pdata_buffer) {
 455                SAM("ERROR: pdata_buffer is NULL\n");
 456                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 457                return -EFAULT;
 458        }
 459        JOM(12, "before wait, %i=frag read  %i=frag fill\n",
 460            (peasycap->audio_read / peasycap->audio_pages_per_fragment),
 461            (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 462        fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
 463        while ((fragment == (peasycap->audio_fill / peasycap->audio_pages_per_fragment)) ||
 464                (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
 465                if (file->f_flags & O_NONBLOCK) {
 466                        JOM(16, "returning -EAGAIN as instructed\n");
 467                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 468                        return -EAGAIN;
 469                }
 470                rc = wait_event_interruptible(peasycap->wq_audio,
 471                                (peasycap->audio_idle  || peasycap->audio_eof ||
 472                                ((fragment !=
 473                                        (peasycap->audio_fill / peasycap->audio_pages_per_fragment)) &&
 474                                (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
 475                if (rc) {
 476                        SAM("aborted by signal\n");
 477                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 478                        return -ERESTARTSYS;
 479                }
 480                if (peasycap->audio_eof) {
 481                        JOM(8, "returning 0 because  %i=audio_eof\n",
 482                            peasycap->audio_eof);
 483                        kill_audio_urbs(peasycap);
 484                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 485                        return 0;
 486                }
 487                if (peasycap->audio_idle) {
 488                        JOM(16, "returning 0 because  %i=audio_idle\n",
 489                            peasycap->audio_idle);
 490                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 491                        return 0;
 492                }
 493                if (!peasycap->audio_isoc_streaming) {
 494                        JOM(16, "returning 0 because audio urbs not streaming\n");
 495                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 496                        return 0;
 497                }
 498        }
 499        JOM(12, "after  wait, %i=frag read  %i=frag fill\n",
 500            (peasycap->audio_read / peasycap->audio_pages_per_fragment),
 501            (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 502        szret = (size_t)0;
 503        fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
 504        while (fragment == (peasycap->audio_read / peasycap->audio_pages_per_fragment)) {
 505                if (!pdata_buffer->pgo) {
 506                        SAM("ERROR: pdata_buffer->pgo is NULL\n");
 507                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 508                        return -EFAULT;
 509                }
 510                if (!pdata_buffer->pto) {
 511                        SAM("ERROR: pdata_buffer->pto is NULL\n");
 512                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 513                        return -EFAULT;
 514                }
 515                kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
 516                if (0 > kount1) {
 517                        SAM("MISTAKE: kount1 is negative\n");
 518                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 519                        return -ERESTARTSYS;
 520                }
 521                if (!kount1) {
 522                        peasycap->audio_read++;
 523                        if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
 524                                peasycap->audio_read = 0;
 525                        JOM(12, "bumped peasycap->audio_read to %i\n",
 526                            peasycap->audio_read);
 527
 528                        if (fragment != (peasycap->audio_read / peasycap->audio_pages_per_fragment))
 529                                break;
 530
 531                        if ((0 > peasycap->audio_read) ||
 532                            (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
 533                                SAM("ERROR: peasycap->audio_read out of range\n");
 534                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 535                                return -EFAULT;
 536                        }
 537                        pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
 538                        if (!pdata_buffer) {
 539                                SAM("ERROR: pdata_buffer is NULL\n");
 540                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 541                                return -EFAULT;
 542                        }
 543                        if (!pdata_buffer->pgo) {
 544                                SAM("ERROR: pdata_buffer->pgo is NULL\n");
 545                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 546                                return -EFAULT;
 547                        }
 548                        if (!pdata_buffer->pto) {
 549                                SAM("ERROR: pdata_buffer->pto is NULL\n");
 550                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 551                                return -EFAULT;
 552                        }
 553                        kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
 554                }
 555                JOM(12, "ready  to send %zd bytes\n", kount1);
 556                JOM(12, "still  to send %li bytes\n", (long int) kount);
 557                more = kount1;
 558                if (more > kount)
 559                        more = kount;
 560                JOM(12, "agreed to send %li bytes from page %i\n",
 561                    more, peasycap->audio_read);
 562                if (!more)
 563                        break;
 564
 565                /*
 566                 *  ACCUMULATE DYNAMIC-RANGE INFORMATION
 567                 */
 568                p0 = (unsigned char *)pdata_buffer->pgo;
 569                l0 = 0;
 570                lm = more/2;
 571                while (l0 < lm) {
 572                        SUMMER(p0, &peasycap->audio_sample,
 573                                &peasycap->audio_niveau,
 574                                &peasycap->audio_square);
 575                        l0++;
 576                        p0 += 2;
 577                }
 578                /*-----------------------------------------------------------*/
 579                rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
 580                if (rc) {
 581                        SAM("ERROR: copy_to_user() returned %li\n", rc);
 582                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 583                        return -EFAULT;
 584                }
 585                *poff += (loff_t)more;
 586                szret += (size_t)more;
 587                pdata_buffer->pto += more;
 588                puserspacebuffer += more;
 589                kount -= (size_t)more;
 590        }
 591        JOM(12, "after  read, %i=frag read  %i=frag fill\n",
 592            (peasycap->audio_read / peasycap->audio_pages_per_fragment),
 593            (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 594        if (kount < 0) {
 595                SAM("MISTAKE:  %li=kount  %li=szret\n",
 596                    (long int)kount, (long int)szret);
 597        }
 598/*---------------------------------------------------------------------------*/
 599/*
 600 *  CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
 601 */
 602/*---------------------------------------------------------------------------*/
 603        if (peasycap->audio_sample) {
 604                below = peasycap->audio_sample;
 605                above = peasycap->audio_square;
 606                sdr = signed_div(above, below);
 607                above = sdr.quotient;
 608                mean = peasycap->audio_niveau;
 609                sdr = signed_div(mean, peasycap->audio_sample);
 610
 611                JOM(8, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n",
 612                    sdr.quotient, above, peasycap->audio_sample);
 613
 614                sdr = signed_div(above, 32768);
 615                JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
 616        }
 617/*---------------------------------------------------------------------------*/
 618/*
 619 *  UPDATE THE AUDIO CLOCK
 620 */
 621/*---------------------------------------------------------------------------*/
 622        do_gettimeofday(&timeval);
 623        if (!peasycap->timeval1.tv_sec) {
 624                peasycap->audio_bytes = 0;
 625                peasycap->timeval3 = timeval;
 626                peasycap->timeval1 = peasycap->timeval3;
 627                sdr.quotient = 192000;
 628        } else {
 629                peasycap->audio_bytes += (long long int) szret;
 630                below = ((long long int)(1000000)) *
 631                        ((long long int)(timeval.tv_sec  - peasycap->timeval3.tv_sec)) +
 632                        (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec);
 633                above = 1000000 * ((long long int) peasycap->audio_bytes);
 634
 635                if (below)
 636                        sdr = signed_div(above, below);
 637                else
 638                        sdr.quotient = 192000;
 639        }
 640        JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
 641        peasycap->dnbydt = sdr.quotient;
 642
 643        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 644        JOM(4, "unlocked easycapdc60_dongle[%i].mutex_audio\n", kd);
 645        JOM(8, "returning %li\n", (long int)szret);
 646        return szret;
 647
 648}
 649/*---------------------------------------------------------------------------*/
 650static long easyoss_unlocked_ioctl(struct file *file,
 651                                   unsigned int cmd, unsigned long arg)
 652{
 653        struct easycap *peasycap;
 654        struct usb_device *p;
 655        int kd;
 656
 657        if (!file) {
 658                SAY("ERROR:  file is NULL\n");
 659                return -ERESTARTSYS;
 660        }
 661        peasycap = file->private_data;
 662        if (!peasycap) {
 663                SAY("ERROR:  peasycap is NULL.\n");
 664                return -EFAULT;
 665        }
 666        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 667                SAY("ERROR: bad peasycap\n");
 668                return -EFAULT;
 669        }
 670        p = peasycap->pusb_device;
 671        if (!p) {
 672                SAM("ERROR: peasycap->pusb_device is NULL\n");
 673                return -EFAULT;
 674        }
 675        kd = isdongle(peasycap);
 676        if (0 <= kd && DONGLE_MANY > kd) {
 677                if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
 678                        SAY("ERROR: cannot lock "
 679                            "easycapdc60_dongle[%i].mutex_audio\n", kd);
 680                        return -ERESTARTSYS;
 681                }
 682                JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
 683                /*
 684                 *  MEANWHILE, easycap_usb_disconnect()
 685                 *  MAY HAVE FREED POINTER peasycap,
 686                 *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
 687                 *  IF NECESSARY, BAIL OUT.
 688                */
 689                if (kd != isdongle(peasycap))
 690                        return -ERESTARTSYS;
 691                if (!file) {
 692                        SAY("ERROR:  file is NULL\n");
 693                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 694                        return -ERESTARTSYS;
 695                }
 696                peasycap = file->private_data;
 697                if (!peasycap) {
 698                        SAY("ERROR:  peasycap is NULL\n");
 699                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 700                        return -ERESTARTSYS;
 701                }
 702                if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 703                        SAY("ERROR: bad peasycap\n");
 704                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 705                        return -EFAULT;
 706                }
 707                p = peasycap->pusb_device;
 708                if (!peasycap->pusb_device) {
 709                        SAM("ERROR: peasycap->pusb_device is NULL\n");
 710                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 711                        return -ERESTARTSYS;
 712                }
 713        } else {
 714                /*
 715                 *  IF easycap_usb_disconnect()
 716                 *  HAS ALREADY FREED POINTER peasycap BEFORE THE
 717                 *  ATTEMPT TO ACQUIRE THE SEMAPHORE,
 718                 *  isdongle() WILL HAVE FAILED.  BAIL OUT.
 719                 */
 720                return -ERESTARTSYS;
 721        }
 722/*---------------------------------------------------------------------------*/
 723        switch (cmd) {
 724        case SNDCTL_DSP_GETCAPS: {
 725                int caps;
 726                JOM(8, "SNDCTL_DSP_GETCAPS\n");
 727
 728#ifdef UPSAMPLE
 729                if (peasycap->microphone)
 730                        caps = 0x04400000;
 731                else
 732                        caps = 0x04400000;
 733#else
 734                if (peasycap->microphone)
 735                        caps = 0x02400000;
 736                else
 737                        caps = 0x04400000;
 738#endif /*UPSAMPLE*/
 739
 740                if (copy_to_user((void __user *)arg, &caps, sizeof(int))) {
 741                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 742                        return -EFAULT;
 743                }
 744                break;
 745        }
 746        case SNDCTL_DSP_GETFMTS: {
 747                int incoming;
 748                JOM(8, "SNDCTL_DSP_GETFMTS\n");
 749
 750#ifdef UPSAMPLE
 751                if (peasycap->microphone)
 752                        incoming = AFMT_S16_LE;
 753                else
 754                        incoming = AFMT_S16_LE;
 755#else
 756                if (peasycap->microphone)
 757                        incoming = AFMT_S16_LE;
 758                else
 759                        incoming = AFMT_S16_LE;
 760#endif /*UPSAMPLE*/
 761
 762                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 763                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 764                        return -EFAULT;
 765                }
 766                break;
 767        }
 768        case SNDCTL_DSP_SETFMT: {
 769                int incoming, outgoing;
 770                JOM(8, "SNDCTL_DSP_SETFMT\n");
 771                if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
 772                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 773                        return -EFAULT;
 774                }
 775                JOM(8, "........... %i=incoming\n", incoming);
 776
 777#ifdef UPSAMPLE
 778                if (peasycap->microphone)
 779                        outgoing = AFMT_S16_LE;
 780                else
 781                        outgoing = AFMT_S16_LE;
 782#else
 783                if (peasycap->microphone)
 784                        outgoing = AFMT_S16_LE;
 785                else
 786                        outgoing = AFMT_S16_LE;
 787#endif /*UPSAMPLE*/
 788
 789                if (incoming != outgoing) {
 790                        JOM(8, "........... %i=outgoing\n", outgoing);
 791                        JOM(8, "        cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
 792                        JOM(8, "        cf. %i=AFMT_U8\n", AFMT_U8);
 793                        if (copy_to_user((void __user *)arg, &outgoing, sizeof(int))) {
 794                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 795                                return -EFAULT;
 796                        }
 797                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 798                        return -EINVAL ;
 799                }
 800                break;
 801        }
 802        case SNDCTL_DSP_STEREO: {
 803                int incoming;
 804                JOM(8, "SNDCTL_DSP_STEREO\n");
 805                if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
 806                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 807                        return -EFAULT;
 808                }
 809                JOM(8, "........... %i=incoming\n", incoming);
 810
 811#ifdef UPSAMPLE
 812                if (peasycap->microphone)
 813                        incoming = 1;
 814                else
 815                        incoming = 1;
 816#else
 817                if (peasycap->microphone)
 818                        incoming = 0;
 819                else
 820                        incoming = 1;
 821#endif /*UPSAMPLE*/
 822
 823                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 824                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 825                        return -EFAULT;
 826                }
 827                break;
 828        }
 829        case SNDCTL_DSP_SPEED: {
 830                int incoming;
 831                JOM(8, "SNDCTL_DSP_SPEED\n");
 832                if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
 833                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 834                        return -EFAULT;
 835                }
 836                JOM(8, "........... %i=incoming\n", incoming);
 837
 838#ifdef UPSAMPLE
 839                if (peasycap->microphone)
 840                        incoming = 32000;
 841                else
 842                        incoming = 48000;
 843#else
 844                if (peasycap->microphone)
 845                        incoming = 8000;
 846                else
 847                        incoming = 48000;
 848#endif /*UPSAMPLE*/
 849
 850                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 851                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 852                        return -EFAULT;
 853                }
 854                break;
 855        }
 856        case SNDCTL_DSP_GETTRIGGER: {
 857                int incoming;
 858                JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
 859                if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
 860                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 861                        return -EFAULT;
 862                }
 863                JOM(8, "........... %i=incoming\n", incoming);
 864
 865                incoming = PCM_ENABLE_INPUT;
 866                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 867                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 868                        return -EFAULT;
 869                }
 870                break;
 871        }
 872        case SNDCTL_DSP_SETTRIGGER: {
 873                int incoming;
 874                JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
 875                if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
 876                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 877                        return -EFAULT;
 878                }
 879                JOM(8, "........... %i=incoming\n", incoming);
 880                JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT "
 881                    "0x%x=PCM_ENABLE_OUTPUT\n",
 882                    PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
 883                ;
 884                ;
 885                ;
 886                ;
 887                break;
 888        }
 889        case SNDCTL_DSP_GETBLKSIZE: {
 890                int incoming;
 891                JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
 892                if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
 893                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 894                        return -EFAULT;
 895                }
 896                JOM(8, "........... %i=incoming\n", incoming);
 897                incoming = peasycap->audio_bytes_per_fragment;
 898                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 899                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 900                        return -EFAULT;
 901                }
 902                break;
 903        }
 904        case SNDCTL_DSP_GETISPACE: {
 905                struct audio_buf_info audio_buf_info;
 906
 907                JOM(8, "SNDCTL_DSP_GETISPACE\n");
 908
 909                audio_buf_info.bytes      = peasycap->audio_bytes_per_fragment;
 910                audio_buf_info.fragments  = 1;
 911                audio_buf_info.fragsize   = 0;
 912                audio_buf_info.fragstotal = 0;
 913
 914                if (copy_to_user((void __user *)arg, &audio_buf_info, sizeof(int))) {
 915                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 916                        return -EFAULT;
 917                }
 918                break;
 919        }
 920        case 0x00005401:
 921        case 0x00005402:
 922        case 0x00005403:
 923        case 0x00005404:
 924        case 0x00005405:
 925        case 0x00005406: {
 926                JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
 927                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 928                return -ENOIOCTLCMD;
 929        }
 930        default: {
 931                JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
 932                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 933                return -ENOIOCTLCMD;
 934        }
 935        }
 936        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 937        return 0;
 938}
 939/*****************************************************************************/
 940
 941static const struct file_operations easyoss_fops = {
 942        .owner          = THIS_MODULE,
 943        .open           = easyoss_open,
 944        .release        = easyoss_release,
 945        .unlocked_ioctl = easyoss_unlocked_ioctl,
 946        .read           = easyoss_read,
 947        .llseek         = no_llseek,
 948};
 949struct usb_class_driver easyoss_class = {
 950        .name = "usb/easyoss%d",
 951        .fops = &easyoss_fops,
 952        .minor_base = USB_SKEL_MINOR_BASE,
 953};
 954/*****************************************************************************/
 955