linux/drivers/staging/easycap/easycap_sound.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#include "easycap_debug.h"
  33#include "easycap_sound.h"
  34
  35/*****************************************************************************/
  36/*---------------------------------------------------------------------------*/
  37/*
  38 *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
  39 *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
  40 *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
  41 */
  42/*---------------------------------------------------------------------------*/
  43void
  44easysnd_complete(struct urb *purb)
  45{
  46struct easycap *peasycap;
  47struct data_buffer *paudio_buffer;
  48__u8 *p1, *p2;
  49__s16 s16;
  50int i, j, more, much, leap, rc;
  51#if defined(UPSAMPLE)
  52int k;
  53__s16 oldaudio, newaudio, delta;
  54#endif /*UPSAMPLE*/
  55
  56JOT(16, "\n");
  57
  58if (NULL == purb) {
  59        SAY("ERROR: purb is NULL\n");
  60        return;
  61}
  62peasycap = purb->context;
  63if (NULL == peasycap) {
  64        SAY("ERROR: peasycap is NULL\n");
  65        return;
  66}
  67if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
  68        SAY("ERROR: bad peasycap\n");
  69        return;
  70}
  71
  72much = 0;
  73
  74if (peasycap->audio_idle) {
  75        JOM(16, "%i=audio_idle  %i=audio_isoc_streaming\n", \
  76                        peasycap->audio_idle, peasycap->audio_isoc_streaming);
  77        if (peasycap->audio_isoc_streaming) {
  78                rc = usb_submit_urb(purb, GFP_ATOMIC);
  79                if (0 != rc) {
  80                        if (-ENODEV != rc)
  81                                SAM("ERROR: while %i=audio_idle, " \
  82                                        "usb_submit_urb() failed with rc:\n", \
  83                                                        peasycap->audio_idle);
  84                        switch (rc) {
  85                        case -ENOMEM: {
  86                                SAM("-ENOMEM\n");
  87                                break;
  88                        }
  89                        case -ENODEV: {
  90                                break;
  91                        }
  92                        case -ENXIO: {
  93                                SAM("-ENXIO\n");
  94                                break;
  95                        }
  96                        case -EINVAL: {
  97                                SAM("-EINVAL\n");
  98                                break;
  99                        }
 100                        case -EAGAIN: {
 101                                SAM("-EAGAIN\n");
 102                                break;
 103                        }
 104                        case -EFBIG: {
 105                                SAM("-EFBIG\n");
 106                                break;
 107                        }
 108                        case -EPIPE: {
 109                                SAM("-EPIPE\n");
 110                                break;
 111                        }
 112                        case -EMSGSIZE: {
 113                                SAM("-EMSGSIZE\n");
 114                                break;
 115                        }
 116                        case -ENOSPC: {
 117                                SAM("-ENOSPC\n");
 118                                break;
 119                        }
 120                        default: {
 121                                SAM("unknown error: 0x%08X\n", rc);
 122                                break;
 123                        }
 124                        }
 125                }
 126        }
 127return;
 128}
 129/*---------------------------------------------------------------------------*/
 130if (purb->status) {
 131        if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
 132                JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
 133                return;
 134        }
 135        SAM("ERROR: non-zero urb status:\n");
 136        switch (purb->status) {
 137        case -EINPROGRESS: {
 138                SAM("-EINPROGRESS\n");
 139                break;
 140        }
 141        case -ENOSR: {
 142                SAM("-ENOSR\n");
 143                break;
 144        }
 145        case -EPIPE: {
 146                SAM("-EPIPE\n");
 147                break;
 148        }
 149        case -EOVERFLOW: {
 150                SAM("-EOVERFLOW\n");
 151                break;
 152        }
 153        case -EPROTO: {
 154                SAM("-EPROTO\n");
 155                break;
 156        }
 157        case -EILSEQ: {
 158                SAM("-EILSEQ\n");
 159                break;
 160        }
 161        case -ETIMEDOUT: {
 162                SAM("-ETIMEDOUT\n");
 163                break;
 164        }
 165        case -EMSGSIZE: {
 166                SAM("-EMSGSIZE\n");
 167                break;
 168        }
 169        case -EOPNOTSUPP: {
 170                SAM("-EOPNOTSUPP\n");
 171                break;
 172        }
 173        case -EPFNOSUPPORT: {
 174                SAM("-EPFNOSUPPORT\n");
 175                break;
 176        }
 177        case -EAFNOSUPPORT: {
 178                SAM("-EAFNOSUPPORT\n");
 179                break;
 180        }
 181        case -EADDRINUSE: {
 182                SAM("-EADDRINUSE\n");
 183                break;
 184        }
 185        case -EADDRNOTAVAIL: {
 186                SAM("-EADDRNOTAVAIL\n");
 187                break;
 188        }
 189        case -ENOBUFS: {
 190                SAM("-ENOBUFS\n");
 191                break;
 192        }
 193        case -EISCONN: {
 194                SAM("-EISCONN\n");
 195                break;
 196        }
 197        case -ENOTCONN: {
 198                SAM("-ENOTCONN\n");
 199                break;
 200        }
 201        case -ESHUTDOWN: {
 202                SAM("-ESHUTDOWN\n");
 203                break;
 204        }
 205        case -ENOENT: {
 206                SAM("-ENOENT\n");
 207                break;
 208        }
 209        case -ECONNRESET: {
 210                SAM("-ECONNRESET\n");
 211                break;
 212        }
 213        case -ENOSPC: {
 214                SAM("ENOSPC\n");
 215                break;
 216        }
 217        default: {
 218                SAM("unknown error code 0x%08X\n", purb->status);
 219                break;
 220        }
 221        }
 222/*---------------------------------------------------------------------------*/
 223/*
 224 *  RESUBMIT THIS URB AFTER AN ERROR
 225 *
 226 *  (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)
 227 */
 228/*---------------------------------------------------------------------------*/
 229        if (peasycap->audio_isoc_streaming) {
 230                rc = usb_submit_urb(purb, GFP_ATOMIC);
 231                if (0 != rc) {
 232                        SAM("ERROR: while %i=audio_idle, usb_submit_urb() "
 233                                "failed with rc:\n", peasycap->audio_idle);
 234                        switch (rc) {
 235                        case -ENOMEM: {
 236                                SAM("-ENOMEM\n");
 237                                break;
 238                        }
 239                        case -ENODEV: {
 240                                SAM("-ENODEV\n");
 241                                break;
 242                        }
 243                        case -ENXIO: {
 244                                SAM("-ENXIO\n");
 245                                break;
 246                        }
 247                        case -EINVAL: {
 248                                SAM("-EINVAL\n");
 249                                break;
 250                        }
 251                        case -EAGAIN: {
 252                                SAM("-EAGAIN\n");
 253                                break;
 254                        }
 255                        case -EFBIG: {
 256                                SAM("-EFBIG\n");
 257                                break;
 258                        }
 259                        case -EPIPE: {
 260                                SAM("-EPIPE\n");
 261                                break;
 262                        }
 263                        case -EMSGSIZE: {
 264                                SAM("-EMSGSIZE\n");
 265                                break;
 266                        }
 267                        default: {
 268                                SAM("0x%08X\n", rc); break;
 269                        }
 270                        }
 271                }
 272        }
 273        return;
 274}
 275/*---------------------------------------------------------------------------*/
 276/*
 277 *  PROCEED HERE WHEN NO ERROR
 278 */
 279/*---------------------------------------------------------------------------*/
 280#if defined(UPSAMPLE)
 281oldaudio = peasycap->oldaudio;
 282#endif /*UPSAMPLE*/
 283
 284for (i = 0;  i < purb->number_of_packets; i++) {
 285        switch (purb->iso_frame_desc[i].status) {
 286        case  0: {
 287                break;
 288        }
 289        case -ENOENT: {
 290                SAM("-ENOENT\n");
 291                break;
 292        }
 293        case -EINPROGRESS: {
 294                SAM("-EINPROGRESS\n");
 295                break;
 296        }
 297        case -EPROTO: {
 298                SAM("-EPROTO\n");
 299                break;
 300        }
 301        case -EILSEQ: {
 302                SAM("-EILSEQ\n");
 303                break;
 304        }
 305        case -ETIME: {
 306                SAM("-ETIME\n");
 307                break;
 308        }
 309        case -ETIMEDOUT: {
 310                SAM("-ETIMEDOUT\n");
 311                break;
 312        }
 313        case -EPIPE: {
 314                SAM("-EPIPE\n");
 315                break;
 316        }
 317        case -ECOMM: {
 318                SAM("-ECOMM\n");
 319                break;
 320        }
 321        case -ENOSR: {
 322                SAM("-ENOSR\n");
 323                break;
 324        }
 325        case -EOVERFLOW: {
 326                SAM("-EOVERFLOW\n");
 327                break;
 328        }
 329        case -EREMOTEIO: {
 330                SAM("-EREMOTEIO\n");
 331                break;
 332        }
 333        case -ENODEV: {
 334                SAM("-ENODEV\n");
 335                break;
 336        }
 337        case -EXDEV: {
 338                SAM("-EXDEV\n");
 339                break;
 340        }
 341        case -EINVAL: {
 342                SAM("-EINVAL\n");
 343                break;
 344        }
 345        case -ECONNRESET: {
 346                SAM("-ECONNRESET\n");
 347                break;
 348        }
 349        case -ENOSPC: {
 350                SAM("-ENOSPC\n");
 351                break;
 352        }
 353        case -ESHUTDOWN: {
 354                SAM("-ESHUTDOWN\n");
 355                break;
 356        }
 357        default: {
 358                SAM("unknown error:0x%08X\n", purb->iso_frame_desc[i].status);
 359                break;
 360        }
 361        }
 362        if (!purb->iso_frame_desc[i].status) {
 363                more = purb->iso_frame_desc[i].actual_length;
 364
 365#if defined(TESTTONE)
 366                if (!more)
 367                        more = purb->iso_frame_desc[i].length;
 368#endif
 369
 370                if (!more)
 371                        peasycap->audio_mt++;
 372                else {
 373                        if (peasycap->audio_mt) {
 374                                JOM(16, "%4i empty audio urb frames\n", \
 375                                                        peasycap->audio_mt);
 376                                peasycap->audio_mt = 0;
 377                        }
 378
 379                        p1 = (__u8 *)(purb->transfer_buffer + \
 380                                        purb->iso_frame_desc[i].offset);
 381
 382                        leap = 0;
 383                        p1 += leap;
 384                        more -= leap;
 385/*---------------------------------------------------------------------------*/
 386/*
 387 *  COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
 388 *  CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY
 389 */
 390/*---------------------------------------------------------------------------*/
 391                        while (more) {
 392                                if (0 > more) {
 393                                        SAM("easysnd_complete: MISTAKE: " \
 394                                                        "more is negative\n");
 395                                        return;
 396                                }
 397                                if (peasycap->audio_buffer_page_many <= \
 398                                                        peasycap->audio_fill) {
 399                                        SAM("ERROR: bad " \
 400                                                "peasycap->audio_fill\n");
 401                                        return;
 402                                }
 403
 404                                paudio_buffer = &peasycap->audio_buffer\
 405                                                        [peasycap->audio_fill];
 406                                if (PAGE_SIZE < (paudio_buffer->pto - \
 407                                                paudio_buffer->pgo)) {
 408                                        SAM("ERROR: bad paudio_buffer->pto\n");
 409                                        return;
 410                                }
 411                                if (PAGE_SIZE == (paudio_buffer->pto - \
 412                                                        paudio_buffer->pgo)) {
 413
 414#if defined(TESTTONE)
 415                                        easysnd_testtone(peasycap, \
 416                                                        peasycap->audio_fill);
 417#endif /*TESTTONE*/
 418
 419                                        paudio_buffer->pto = \
 420                                                        paudio_buffer->pgo;
 421                                        (peasycap->audio_fill)++;
 422                                        if (peasycap->\
 423                                                audio_buffer_page_many <= \
 424                                                        peasycap->audio_fill)
 425                                                peasycap->audio_fill = 0;
 426
 427                                        JOM(12, "bumped peasycap->" \
 428                                                        "audio_fill to %i\n", \
 429                                                        peasycap->audio_fill);
 430
 431                                        paudio_buffer = &peasycap->\
 432                                                        audio_buffer\
 433                                                        [peasycap->audio_fill];
 434                                        paudio_buffer->pto = \
 435                                                        paudio_buffer->pgo;
 436
 437                                        if (!(peasycap->audio_fill % \
 438                                                peasycap->\
 439                                                audio_pages_per_fragment)) {
 440                                                JOM(12, "wakeup call on wq_" \
 441                                                "audio, %i=frag reading  %i" \
 442                                                "=fragment fill\n", \
 443                                                (peasycap->audio_read / \
 444                                                peasycap->\
 445                                                audio_pages_per_fragment), \
 446                                                (peasycap->audio_fill / \
 447                                                peasycap->\
 448                                                audio_pages_per_fragment));
 449                                                wake_up_interruptible\
 450                                                (&(peasycap->wq_audio));
 451                                        }
 452                                }
 453
 454                                much = PAGE_SIZE - (int)(paudio_buffer->pto -\
 455                                                         paudio_buffer->pgo);
 456
 457                                if (false == peasycap->microphone) {
 458                                        if (much > more)
 459                                                much = more;
 460
 461                                        memcpy(paudio_buffer->pto, p1, much);
 462                                        p1 += much;
 463                                        more -= much;
 464                                } else {
 465#if defined(UPSAMPLE)
 466                                        if (much % 16)
 467                                                JOM(8, "MISTAKE? much" \
 468                                                " is not divisible by 16\n");
 469                                        if (much > (16 * \
 470                                                        more))
 471                                                much = 16 * \
 472                                                        more;
 473                                        p2 = (__u8 *)paudio_buffer->pto;
 474
 475                                        for (j = 0;  j < (much/16);  j++) {
 476                                                newaudio =  ((int) *p1) - 128;
 477                                                newaudio = 128 * \
 478                                                                newaudio;
 479
 480                                                delta = (newaudio - oldaudio) \
 481                                                                        / 4;
 482                                                s16 = oldaudio + delta;
 483
 484                                                for (k = 0;  k < 4;  k++) {
 485                                                        *p2 = (0x00FF & s16);
 486                                                        *(p2 + 1) = (0xFF00 & \
 487                                                                s16) >> 8;
 488                                                        p2 += 2;
 489                                                        *p2 = (0x00FF & s16);
 490                                                        *(p2 + 1) = (0xFF00 & \
 491                                                                s16) >> 8;
 492                                                        p2 += 2;
 493
 494                                                        s16 += delta;
 495                                                }
 496                                                p1++;
 497                                                more--;
 498                                                oldaudio = s16;
 499                                        }
 500#else
 501                                        if (much > (2 * more))
 502                                                much = 2 * more;
 503                                        p2 = (__u8 *)paudio_buffer->pto;
 504
 505                                        for (j = 0;  j < (much / 2);  j++) {
 506                                                s16 =  ((int) *p1) - 128;
 507                                                s16 = 128 * \
 508                                                                s16;
 509                                                *p2 = (0x00FF & s16);
 510                                                *(p2 + 1) = (0xFF00 & s16) >> \
 511                                                                        8;
 512                                                p1++;  p2 += 2;
 513                                                more--;
 514                                        }
 515#endif /*UPSAMPLE*/
 516                                }
 517                                (paudio_buffer->pto) += much;
 518                        }
 519                }
 520        } else {
 521                JOM(12, "discarding audio samples because " \
 522                        "%i=purb->iso_frame_desc[i].status\n", \
 523                                purb->iso_frame_desc[i].status);
 524        }
 525
 526#if defined(UPSAMPLE)
 527peasycap->oldaudio = oldaudio;
 528#endif /*UPSAMPLE*/
 529
 530}
 531/*---------------------------------------------------------------------------*/
 532/*
 533 *  RESUBMIT THIS URB AFTER NO ERROR
 534 */
 535/*---------------------------------------------------------------------------*/
 536if (peasycap->audio_isoc_streaming) {
 537        rc = usb_submit_urb(purb, GFP_ATOMIC);
 538        if (0 != rc) {
 539                if (-ENODEV != rc) {
 540                        SAM("ERROR: while %i=audio_idle, " \
 541                                        "usb_submit_urb() failed " \
 542                                        "with rc:\n", peasycap->audio_idle);
 543                }
 544                switch (rc) {
 545                case -ENOMEM: {
 546                        SAM("-ENOMEM\n");
 547                        break;
 548                }
 549                case -ENODEV: {
 550                        break;
 551                }
 552                case -ENXIO: {
 553                        SAM("-ENXIO\n");
 554                        break;
 555                }
 556                case -EINVAL: {
 557                        SAM("-EINVAL\n");
 558                        break;
 559                }
 560                case -EAGAIN: {
 561                        SAM("-EAGAIN\n");
 562                        break;
 563                }
 564                case -EFBIG: {
 565                        SAM("-EFBIG\n");
 566                        break;
 567                }
 568                case -EPIPE: {
 569                        SAM("-EPIPE\n");
 570                        break;
 571                }
 572                case -EMSGSIZE: {
 573                        SAM("-EMSGSIZE\n");
 574                        break;
 575                }
 576                case -ENOSPC: {
 577                        SAM("-ENOSPC\n");
 578                        break;
 579                }
 580                default: {
 581                        SAM("unknown error: 0x%08X\n", rc);
 582                        break;
 583                }
 584                }
 585        }
 586}
 587return;
 588}
 589/*****************************************************************************/
 590/*---------------------------------------------------------------------------*/
 591/*
 592 *  THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
 593 *  STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
 594 *  HAVE AN IOCTL INTERFACE.
 595 */
 596/*---------------------------------------------------------------------------*/
 597int
 598easysnd_open(struct inode *inode, struct file *file)
 599{
 600struct usb_interface *pusb_interface;
 601struct easycap *peasycap;
 602int subminor, rc;
 603/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
 604#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
 605#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
 606struct v4l2_device *pv4l2_device;
 607#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
 608#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
 609/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
 610
 611JOT(4, "begins\n");
 612
 613subminor = iminor(inode);
 614
 615pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
 616if (NULL == pusb_interface) {
 617        SAY("ERROR: pusb_interface is NULL\n");
 618        SAY("ending unsuccessfully\n");
 619        return -1;
 620}
 621peasycap = usb_get_intfdata(pusb_interface);
 622if (NULL == peasycap) {
 623        SAY("ERROR: peasycap is NULL\n");
 624        SAY("ending unsuccessfully\n");
 625        return -1;
 626}
 627/*---------------------------------------------------------------------------*/
 628#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
 629#
 630/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
 631#else
 632#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
 633/*---------------------------------------------------------------------------*/
 634/*
 635 *  SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
 636 *  BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
 637 *  REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
 638 *  TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
 639*/
 640/*---------------------------------------------------------------------------*/
 641if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 642        pv4l2_device = usb_get_intfdata(pusb_interface);
 643        if ((struct v4l2_device *)NULL == pv4l2_device) {
 644                SAY("ERROR: pv4l2_device is NULL\n");
 645                return -EFAULT;
 646        }
 647        peasycap = (struct easycap *) \
 648                container_of(pv4l2_device, struct easycap, v4l2_device);
 649}
 650#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
 651#
 652#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
 653/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
 654/*---------------------------------------------------------------------------*/
 655if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 656        SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
 657        return -EFAULT;
 658}
 659/*---------------------------------------------------------------------------*/
 660
 661file->private_data = peasycap;
 662
 663/*---------------------------------------------------------------------------*/
 664/*
 665 *  INITIALIZATION
 666 */
 667/*---------------------------------------------------------------------------*/
 668JOM(4, "starting initialization\n");
 669
 670if ((struct usb_device *)NULL == peasycap->pusb_device) {
 671        SAM("ERROR: peasycap->pusb_device is NULL\n");
 672        return -ENODEV;
 673}
 674JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
 675
 676rc = audio_setup(peasycap);
 677if (0 <= rc)
 678        JOM(8, "audio_setup() returned %i\n", rc);
 679else
 680        JOM(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
 681
 682if ((struct usb_device *)NULL == peasycap->pusb_device) {
 683        SAM("ERROR: peasycap->pusb_device has become NULL\n");
 684        return -ENODEV;
 685}
 686/*---------------------------------------------------------------------------*/
 687if ((struct usb_device *)NULL == peasycap->pusb_device) {
 688        SAM("ERROR: peasycap->pusb_device has become NULL\n");
 689        return -ENODEV;
 690}
 691rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
 692                                        peasycap->audio_altsetting_on);
 693JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
 694                                        peasycap->audio_altsetting_on, rc);
 695
 696rc = wakeup_device(peasycap->pusb_device);
 697if (0 == rc)
 698        JOM(8, "wakeup_device() returned %i\n", rc);
 699else
 700        JOM(8, "ERROR: wakeup_device() returned %i\n", rc);
 701
 702peasycap->audio_eof = 0;
 703peasycap->audio_idle = 0;
 704
 705peasycap->timeval1.tv_sec  = 0;
 706peasycap->timeval1.tv_usec = 0;
 707
 708submit_audio_urbs(peasycap);
 709
 710JOM(4, "finished initialization\n");
 711return 0;
 712}
 713/*****************************************************************************/
 714int
 715easysnd_release(struct inode *inode, struct file *file)
 716{
 717struct easycap *peasycap;
 718
 719JOT(4, "begins\n");
 720
 721peasycap = file->private_data;
 722if (NULL == peasycap) {
 723        SAY("ERROR:  peasycap is NULL.\n");
 724        return -EFAULT;
 725}
 726if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 727        SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
 728        return -EFAULT;
 729}
 730if (0 != kill_audio_urbs(peasycap)) {
 731        SAM("ERROR: kill_audio_urbs() failed\n");
 732        return -EFAULT;
 733}
 734JOM(4, "ending successfully\n");
 735return 0;
 736}
 737/*****************************************************************************/
 738ssize_t
 739easysnd_read(struct file *file, char __user *puserspacebuffer, \
 740                                                size_t kount, loff_t *poff)
 741{
 742struct timeval timeval;
 743long long int above, below, mean;
 744struct signed_div_result sdr;
 745unsigned char *p0;
 746long int kount1, more, rc, l0, lm;
 747int fragment, kd;
 748struct easycap *peasycap;
 749struct data_buffer *pdata_buffer;
 750size_t szret;
 751
 752/*---------------------------------------------------------------------------*/
 753/*
 754 *  DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
 755 *
 756 ******************************************************************************
 757 *****  N.B.  IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
 758 *****        THIS CONDITION SIGNIFIES END-OF-FILE.                      ******
 759 ******************************************************************************
 760 */
 761/*---------------------------------------------------------------------------*/
 762
 763JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
 764
 765if (NULL == file) {
 766        SAY("ERROR:  file is NULL\n");
 767        return -ERESTARTSYS;
 768}
 769peasycap = file->private_data;
 770if (NULL == peasycap) {
 771        SAY("ERROR in easysnd_read(): peasycap is NULL\n");
 772        return -EFAULT;
 773}
 774if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 775        SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
 776        return -EFAULT;
 777}
 778if (NULL == peasycap->pusb_device) {
 779        SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n");
 780        return -EFAULT;
 781}
 782kd = isdongle(peasycap);
 783if (0 <= kd && DONGLE_MANY > kd) {
 784        if (mutex_lock_interruptible(&(easycap_dongle[kd].mutex_audio))) {
 785                SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
 786                return -ERESTARTSYS;
 787        }
 788        JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
 789/*---------------------------------------------------------------------------*/
 790/*
 791 *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
 792 *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
 793 *  IF NECESSARY, BAIL OUT.
 794*/
 795/*---------------------------------------------------------------------------*/
 796        if (kd != isdongle(peasycap))
 797                return -ERESTARTSYS;
 798        if (NULL == file) {
 799                SAY("ERROR:  file is NULL\n");
 800                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 801                return -ERESTARTSYS;
 802        }
 803        peasycap = file->private_data;
 804        if (NULL == peasycap) {
 805                SAY("ERROR:  peasycap is NULL\n");
 806                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 807                return -ERESTARTSYS;
 808        }
 809        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 810                SAY("ERROR: bad peasycap: 0x%08lX\n", \
 811                                                (unsigned long int) peasycap);
 812                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 813                return -ERESTARTSYS;
 814        }
 815        if (NULL == peasycap->pusb_device) {
 816                SAM("ERROR: peasycap->pusb_device is NULL\n");
 817                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 818                return -ERESTARTSYS;
 819        }
 820} else {
 821/*---------------------------------------------------------------------------*/
 822/*
 823 *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
 824 *  ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED.  BAIL OUT.
 825*/
 826/*---------------------------------------------------------------------------*/
 827        return -ERESTARTSYS;
 828}
 829/*---------------------------------------------------------------------------*/
 830if (file->f_flags & O_NONBLOCK)
 831        JOT(16, "NONBLOCK  kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
 832else
 833        JOT(8, "BLOCKING  kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
 834
 835if ((0 > peasycap->audio_read) || \
 836                (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
 837        SAM("ERROR: peasycap->audio_read out of range\n");
 838        mutex_unlock(&easycap_dongle[kd].mutex_audio);
 839        return -EFAULT;
 840}
 841pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
 842if ((struct data_buffer *)NULL == pdata_buffer) {
 843        SAM("ERROR: pdata_buffer is NULL\n");
 844        mutex_unlock(&easycap_dongle[kd].mutex_audio);
 845        return -EFAULT;
 846}
 847JOM(12, "before wait, %i=frag read  %i=frag fill\n", \
 848                (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
 849                (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 850fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
 851while ((fragment == (peasycap->audio_fill / \
 852                                peasycap->audio_pages_per_fragment)) || \
 853                (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
 854        if (file->f_flags & O_NONBLOCK) {
 855                JOM(16, "returning -EAGAIN as instructed\n");
 856                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 857                return -EAGAIN;
 858        }
 859        rc = wait_event_interruptible(peasycap->wq_audio, \
 860                (peasycap->audio_idle  || peasycap->audio_eof   || \
 861                ((fragment != (peasycap->audio_fill / \
 862                                peasycap->audio_pages_per_fragment)) && \
 863                (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
 864        if (0 != rc) {
 865                SAM("aborted by signal\n");
 866                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 867                return -ERESTARTSYS;
 868        }
 869        if (peasycap->audio_eof) {
 870                JOM(8, "returning 0 because  %i=audio_eof\n", \
 871                                                        peasycap->audio_eof);
 872                kill_audio_urbs(peasycap);
 873                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 874                return 0;
 875        }
 876        if (peasycap->audio_idle) {
 877                JOM(16, "returning 0 because  %i=audio_idle\n", \
 878                                                        peasycap->audio_idle);
 879                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 880                return 0;
 881        }
 882        if (!peasycap->audio_isoc_streaming) {
 883                JOM(16, "returning 0 because audio urbs not streaming\n");
 884                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 885                return 0;
 886        }
 887}
 888JOM(12, "after  wait, %i=frag read  %i=frag fill\n", \
 889                (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
 890                (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 891szret = (size_t)0;
 892while (fragment == (peasycap->audio_read / \
 893                                peasycap->audio_pages_per_fragment)) {
 894        if (NULL == pdata_buffer->pgo) {
 895                SAM("ERROR: pdata_buffer->pgo is NULL\n");
 896                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 897                return -EFAULT;
 898        }
 899        if (NULL == pdata_buffer->pto) {
 900                SAM("ERROR: pdata_buffer->pto is NULL\n");
 901                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 902                return -EFAULT;
 903        }
 904        kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
 905        if (0 > kount1) {
 906                SAM("easysnd_read: MISTAKE: kount1 is negative\n");
 907                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 908                return -ERESTARTSYS;
 909        }
 910        if (!kount1) {
 911                (peasycap->audio_read)++;
 912                if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
 913                        peasycap->audio_read = 0;
 914                JOM(12, "bumped peasycap->audio_read to %i\n", \
 915                                                peasycap->audio_read);
 916
 917                if (fragment != (peasycap->audio_read / \
 918                                        peasycap->audio_pages_per_fragment))
 919                        break;
 920
 921                if ((0 > peasycap->audio_read) || \
 922                        (peasycap->audio_buffer_page_many <= \
 923                                        peasycap->audio_read)) {
 924                        SAM("ERROR: peasycap->audio_read out of range\n");
 925                        mutex_unlock(&easycap_dongle[kd].mutex_audio);
 926                        return -EFAULT;
 927                }
 928                pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
 929                if ((struct data_buffer *)NULL == pdata_buffer) {
 930                        SAM("ERROR: pdata_buffer is NULL\n");
 931                        mutex_unlock(&easycap_dongle[kd].mutex_audio);
 932                        return -EFAULT;
 933                }
 934                if (NULL == pdata_buffer->pgo) {
 935                        SAM("ERROR: pdata_buffer->pgo is NULL\n");
 936                        mutex_unlock(&easycap_dongle[kd].mutex_audio);
 937                        return -EFAULT;
 938                }
 939                if (NULL == pdata_buffer->pto) {
 940                        SAM("ERROR: pdata_buffer->pto is NULL\n");
 941                        mutex_unlock(&easycap_dongle[kd].mutex_audio);
 942                        return -EFAULT;
 943                }
 944                kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
 945        }
 946        JOM(12, "ready  to send %li bytes\n", (long int) kount1);
 947        JOM(12, "still  to send %li bytes\n", (long int) kount);
 948        more = kount1;
 949        if (more > kount)
 950                more = kount;
 951        JOM(12, "agreed to send %li bytes from page %i\n", \
 952                                                more, peasycap->audio_read);
 953        if (!more)
 954                break;
 955
 956/*---------------------------------------------------------------------------*/
 957/*
 958 *  ACCUMULATE DYNAMIC-RANGE INFORMATION
 959 */
 960/*---------------------------------------------------------------------------*/
 961        p0 = (unsigned char *)pdata_buffer->pgo;  l0 = 0;  lm = more/2;
 962        while (l0 < lm) {
 963                SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau, \
 964                                &peasycap->audio_square);  l0++;  p0 += 2;
 965        }
 966/*---------------------------------------------------------------------------*/
 967        rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
 968        if (0 != rc) {
 969                SAM("ERROR: copy_to_user() returned %li\n", rc);
 970                mutex_unlock(&easycap_dongle[kd].mutex_audio);
 971                return -EFAULT;
 972        }
 973        *poff += (loff_t)more;
 974        szret += (size_t)more;
 975        pdata_buffer->pto += more;
 976        puserspacebuffer += more;
 977        kount -= (size_t)more;
 978}
 979JOM(12, "after  read, %i=frag read  %i=frag fill\n", \
 980                (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
 981                (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
 982if (kount < 0) {
 983        SAM("MISTAKE:  %li=kount  %li=szret\n", \
 984                                        (long int)kount, (long int)szret);
 985}
 986/*---------------------------------------------------------------------------*/
 987/*
 988 *  CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
 989 */
 990/*---------------------------------------------------------------------------*/
 991if (peasycap->audio_sample) {
 992        below = peasycap->audio_sample;
 993        above = peasycap->audio_square;
 994        sdr = signed_div(above, below);
 995        above = sdr.quotient;
 996        mean = peasycap->audio_niveau;
 997        sdr = signed_div(mean, peasycap->audio_sample);
 998
 999        JOM(8, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n", \
1000                                sdr.quotient, above, peasycap->audio_sample);
1001
1002        sdr = signed_div(above, 32768);
1003        JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
1004}
1005/*---------------------------------------------------------------------------*/
1006/*
1007 *  UPDATE THE AUDIO CLOCK
1008 */
1009/*---------------------------------------------------------------------------*/
1010do_gettimeofday(&timeval);
1011if (!peasycap->timeval1.tv_sec) {
1012        peasycap->audio_bytes = 0;
1013        peasycap->timeval3 = timeval;
1014        peasycap->timeval1 = peasycap->timeval3;
1015        sdr.quotient = 192000;
1016} else {
1017        peasycap->audio_bytes += (long long int) szret;
1018        below = ((long long int)(1000000)) * \
1019                ((long long int)(timeval.tv_sec  - \
1020                                                peasycap->timeval3.tv_sec)) + \
1021                (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec);
1022        above = 1000000 * ((long long int) peasycap->audio_bytes);
1023
1024        if (below)
1025                sdr = signed_div(above, below);
1026        else
1027                sdr.quotient = 192000;
1028}
1029JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
1030peasycap->dnbydt = sdr.quotient;
1031
1032JOM(8, "returning %li\n", (long int)szret);
1033mutex_unlock(&easycap_dongle[kd].mutex_audio);
1034return szret;
1035}
1036/*****************************************************************************/
1037/*---------------------------------------------------------------------------*/
1038/*
1039 *  SUBMIT ALL AUDIO URBS.
1040 */
1041/*---------------------------------------------------------------------------*/
1042int
1043submit_audio_urbs(struct easycap *peasycap)
1044{
1045struct data_urb *pdata_urb;
1046struct urb *purb;
1047struct list_head *plist_head;
1048int j, isbad, nospc, m, rc;
1049int isbuf;
1050
1051if (NULL == peasycap) {
1052        SAY("ERROR: peasycap is NULL\n");
1053        return -EFAULT;
1054}
1055if ((struct list_head *)NULL == peasycap->purb_audio_head) {
1056        SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
1057        return -EFAULT;
1058}
1059if ((struct usb_device *)NULL == peasycap->pusb_device) {
1060        SAM("ERROR: peasycap->pusb_device is NULL\n");
1061        return -EFAULT;
1062}
1063if (!peasycap->audio_isoc_streaming) {
1064        JOM(4, "initial submission of all audio urbs\n");
1065        rc = usb_set_interface(peasycap->pusb_device,
1066                                        peasycap->audio_interface, \
1067                                        peasycap->audio_altsetting_on);
1068        JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", \
1069                                        peasycap->audio_interface, \
1070                                        peasycap->audio_altsetting_on, rc);
1071
1072        isbad = 0;  nospc = 0;  m = 0;
1073        list_for_each(plist_head, (peasycap->purb_audio_head)) {
1074                pdata_urb = list_entry(plist_head, struct data_urb, list_head);
1075                if (NULL != pdata_urb) {
1076                        purb = pdata_urb->purb;
1077                        if (NULL != purb) {
1078                                isbuf = pdata_urb->isbuf;
1079
1080                                purb->interval = 1;
1081                                purb->dev = peasycap->pusb_device;
1082                                purb->pipe = \
1083                                        usb_rcvisocpipe(peasycap->pusb_device,\
1084                                        peasycap->audio_endpointnumber);
1085                                purb->transfer_flags = URB_ISO_ASAP;
1086                                purb->transfer_buffer = \
1087                                        peasycap->audio_isoc_buffer[isbuf].pgo;
1088                                purb->transfer_buffer_length = \
1089                                        peasycap->audio_isoc_buffer_size;
1090                                purb->complete = easysnd_complete;
1091                                purb->context = peasycap;
1092                                purb->start_frame = 0;
1093                                purb->number_of_packets = \
1094                                        peasycap->audio_isoc_framesperdesc;
1095                                for (j = 0;  j < peasycap->\
1096                                                audio_isoc_framesperdesc; \
1097                                                                        j++) {
1098                                        purb->iso_frame_desc[j].offset = j * \
1099                                                peasycap->\
1100                                                audio_isoc_maxframesize;
1101                                        purb->iso_frame_desc[j].length = \
1102                                                peasycap->\
1103                                                audio_isoc_maxframesize;
1104                                }
1105
1106                                rc = usb_submit_urb(purb, GFP_KERNEL);
1107                                if (0 != rc) {
1108                                        isbad++;
1109                                        SAM("ERROR: usb_submit_urb() failed" \
1110                                                        " for urb with rc:\n");
1111                                        switch (rc) {
1112                                        case -ENOMEM: {
1113                                                SAM("-ENOMEM\n");
1114                                                break;
1115                                        }
1116                                        case -ENODEV: {
1117                                                SAM("-ENODEV\n");
1118                                                break;
1119                                        }
1120                                        case -ENXIO: {
1121                                                SAM("-ENXIO\n");
1122                                                break;
1123                                        }
1124                                        case -EINVAL: {
1125                                                SAM("-EINVAL\n");
1126                                                break;
1127                                        }
1128                                        case -EAGAIN: {
1129                                                SAM("-EAGAIN\n");
1130                                                break;
1131                                        }
1132                                        case -EFBIG: {
1133                                                SAM("-EFBIG\n");
1134                                                break;
1135                                        }
1136                                        case -EPIPE: {
1137                                                SAM("-EPIPE\n");
1138                                                break;
1139                                        }
1140                                        case -EMSGSIZE: {
1141                                                SAM("-EMSGSIZE\n");
1142                                                break;
1143                                        }
1144                                        case -ENOSPC: {
1145                                                nospc++;
1146                                                break;
1147                                        }
1148                                        default: {
1149                                                SAM("unknown error code %i\n",\
1150                                                                 rc);
1151                                                break;
1152                                        }
1153                                        }
1154                                } else {
1155                                         m++;
1156                                }
1157                        } else {
1158                                isbad++;
1159                        }
1160                } else {
1161                        isbad++;
1162                }
1163        }
1164        if (nospc) {
1165                SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
1166                SAM(".....  possibly inadequate USB bandwidth\n");
1167                peasycap->audio_eof = 1;
1168        }
1169        if (isbad) {
1170                JOM(4, "attempting cleanup instead of submitting\n");
1171                list_for_each(plist_head, (peasycap->purb_audio_head)) {
1172                        pdata_urb = list_entry(plist_head, struct data_urb, \
1173                                                                list_head);
1174                        if (NULL != pdata_urb) {
1175                                purb = pdata_urb->purb;
1176                                if (NULL != purb)
1177                                        usb_kill_urb(purb);
1178                        }
1179                }
1180                peasycap->audio_isoc_streaming = 0;
1181        } else {
1182                peasycap->audio_isoc_streaming = 1;
1183                JOM(4, "submitted %i audio urbs\n", m);
1184        }
1185} else
1186        JOM(4, "already streaming audio urbs\n");
1187
1188return 0;
1189}
1190/*****************************************************************************/
1191/*---------------------------------------------------------------------------*/
1192/*
1193 *  KILL ALL AUDIO URBS.
1194 */
1195/*---------------------------------------------------------------------------*/
1196int
1197kill_audio_urbs(struct easycap *peasycap)
1198{
1199int m;
1200struct list_head *plist_head;
1201struct data_urb *pdata_urb;
1202
1203if (NULL == peasycap) {
1204        SAY("ERROR: peasycap is NULL\n");
1205        return -EFAULT;
1206}
1207if (peasycap->audio_isoc_streaming) {
1208        if ((struct list_head *)NULL != peasycap->purb_audio_head) {
1209                peasycap->audio_isoc_streaming = 0;
1210                JOM(4, "killing audio urbs\n");
1211                m = 0;
1212                list_for_each(plist_head, (peasycap->purb_audio_head)) {
1213                        pdata_urb = list_entry(plist_head, struct data_urb,
1214                                                                list_head);
1215                        if ((struct data_urb *)NULL != pdata_urb) {
1216                                if ((struct urb *)NULL != pdata_urb->purb) {
1217                                        usb_kill_urb(pdata_urb->purb);
1218                                        m++;
1219                                }
1220                        }
1221                }
1222                JOM(4, "%i audio urbs killed\n", m);
1223        } else {
1224                SAM("ERROR: peasycap->purb_audio_head is NULL\n");
1225                return -EFAULT;
1226        }
1227} else {
1228        JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
1229                                        peasycap->audio_isoc_streaming);
1230}
1231return 0;
1232}
1233/*****************************************************************************/
1234