1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Conexant Cx231xx audio extension 4 * 5 * Copyright (C) 2008 <srinivasa.deevi at conexant dot com> 6 * Based on em28xx driver 7 */ 8 9 #include "cx231xx.h" 10 #include <linux/kernel.h> 11 #include <linux/init.h> 12 #include <linux/sound.h> 13 #include <linux/spinlock.h> 14 #include <linux/soundcard.h> 15 #include <linux/slab.h> 16 #include <linux/vmalloc.h> 17 #include <linux/proc_fs.h> 18 #include <linux/module.h> 19 #include <sound/core.h> 20 #include <sound/pcm.h> 21 #include <sound/pcm_params.h> 22 #include <sound/info.h> 23 #include <sound/initval.h> 24 #include <sound/control.h> 25 #include <media/v4l2-common.h> 26 27 static int debug; 28 module_param(debug, int, 0644); 29 MODULE_PARM_DESC(debug, "activates debug info"); 30 31 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 32 33 static int cx231xx_isoc_audio_deinit(struct cx231xx *dev) 34 { 35 int i; 36 37 dev_dbg(dev->dev, "Stopping isoc\n"); 38 39 for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { 40 if (dev->adev.urb[i]) { 41 if (!irqs_disabled()) 42 usb_kill_urb(dev->adev.urb[i]); 43 else 44 usb_unlink_urb(dev->adev.urb[i]); 45 46 usb_free_urb(dev->adev.urb[i]); 47 dev->adev.urb[i] = NULL; 48 49 kfree(dev->adev.transfer_buffer[i]); 50 dev->adev.transfer_buffer[i] = NULL; 51 } 52 } 53 54 return 0; 55 } 56 57 static int cx231xx_bulk_audio_deinit(struct cx231xx *dev) 58 { 59 int i; 60 61 dev_dbg(dev->dev, "Stopping bulk\n"); 62 63 for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { 64 if (dev->adev.urb[i]) { 65 if (!irqs_disabled()) 66 usb_kill_urb(dev->adev.urb[i]); 67 else 68 usb_unlink_urb(dev->adev.urb[i]); 69 70 usb_free_urb(dev->adev.urb[i]); 71 dev->adev.urb[i] = NULL; 72 73 kfree(dev->adev.transfer_buffer[i]); 74 dev->adev.transfer_buffer[i] = NULL; 75 } 76 } 77 78 return 0; 79 } 80 81 static void cx231xx_audio_isocirq(struct urb *urb) 82 { 83 struct cx231xx *dev = urb->context; 84 int i; 85 unsigned int oldptr; 86 int period_elapsed = 0; 87 int status; 88 unsigned char *cp; 89 unsigned int stride; 90 struct snd_pcm_substream *substream; 91 struct snd_pcm_runtime *runtime; 92 93 if (dev->state & DEV_DISCONNECTED) 94 return; 95 96 switch (urb->status) { 97 case 0: /* success */ 98 case -ETIMEDOUT: /* NAK */ 99 break; 100 case -ECONNRESET: /* kill */ 101 case -ENOENT: 102 case -ESHUTDOWN: 103 return; 104 default: /* error */ 105 dev_dbg(dev->dev, "urb completion error %d.\n", 106 urb->status); 107 break; 108 } 109 110 if (atomic_read(&dev->stream_started) == 0) 111 return; 112 113 if (dev->adev.capture_pcm_substream) { 114 substream = dev->adev.capture_pcm_substream; 115 runtime = substream->runtime; 116 stride = runtime->frame_bits >> 3; 117 118 for (i = 0; i < urb->number_of_packets; i++) { 119 unsigned long flags; 120 int length = urb->iso_frame_desc[i].actual_length / 121 stride; 122 cp = (unsigned char *)urb->transfer_buffer + 123 urb->iso_frame_desc[i].offset; 124 125 if (!length) 126 continue; 127 128 oldptr = dev->adev.hwptr_done_capture; 129 if (oldptr + length >= runtime->buffer_size) { 130 unsigned int cnt; 131 132 cnt = runtime->buffer_size - oldptr; 133 memcpy(runtime->dma_area + oldptr * stride, cp, 134 cnt * stride); 135 memcpy(runtime->dma_area, cp + cnt * stride, 136 length * stride - cnt * stride); 137 } else { 138 memcpy(runtime->dma_area + oldptr * stride, cp, 139 length * stride); 140 } 141 142 snd_pcm_stream_lock_irqsave(substream, flags); 143 144 dev->adev.hwptr_done_capture += length; 145 if (dev->adev.hwptr_done_capture >= 146 runtime->buffer_size) 147 dev->adev.hwptr_done_capture -= 148 runtime->buffer_size; 149 150 dev->adev.capture_transfer_done += length; 151 if (dev->adev.capture_transfer_done >= 152 runtime->period_size) { 153 dev->adev.capture_transfer_done -= 154 runtime->period_size; 155 period_elapsed = 1; 156 } 157 snd_pcm_stream_unlock_irqrestore(substream, flags); 158 } 159 if (period_elapsed) 160 snd_pcm_period_elapsed(substream); 161 } 162 urb->status = 0; 163 164 status = usb_submit_urb(urb, GFP_ATOMIC); 165 if (status < 0) { 166 dev_err(dev->dev, 167 "resubmit of audio urb failed (error=%i)\n", 168 status); 169 } 170 return; 171 } 172 173 static void cx231xx_audio_bulkirq(struct urb *urb) 174 { 175 struct cx231xx *dev = urb->context; 176 unsigned int oldptr; 177 int period_elapsed = 0; 178 int status; 179 unsigned char *cp; 180 unsigned int stride; 181 struct snd_pcm_substream *substream; 182 struct snd_pcm_runtime *runtime; 183 184 if (dev->state & DEV_DISCONNECTED) 185 return; 186 187 switch (urb->status) { 188 case 0: /* success */ 189 case -ETIMEDOUT: /* NAK */ 190 break; 191 case -ECONNRESET: /* kill */ 192 case -ENOENT: 193 case -ESHUTDOWN: 194 return; 195 default: /* error */ 196 dev_dbg(dev->dev, "urb completion error %d.\n", 197 urb->status); 198 break; 199 } 200 201 if (atomic_read(&dev->stream_started) == 0) 202 return; 203 204 if (dev->adev.capture_pcm_substream) { 205 substream = dev->adev.capture_pcm_substream; 206 runtime = substream->runtime; 207 stride = runtime->frame_bits >> 3; 208 209 if (1) { 210 unsigned long flags; 211 int length = urb->actual_length / 212 stride; 213 cp = (unsigned char *)urb->transfer_buffer; 214 215 oldptr = dev->adev.hwptr_done_capture; 216 if (oldptr + length >= runtime->buffer_size) { 217 unsigned int cnt; 218 219 cnt = runtime->buffer_size - oldptr; 220 memcpy(runtime->dma_area + oldptr * stride, cp, 221 cnt * stride); 222 memcpy(runtime->dma_area, cp + cnt * stride, 223 length * stride - cnt * stride); 224 } else { 225 memcpy(runtime->dma_area + oldptr * stride, cp, 226 length * stride); 227 } 228 229 snd_pcm_stream_lock_irqsave(substream, flags); 230 231 dev->adev.hwptr_done_capture += length; 232 if (dev->adev.hwptr_done_capture >= 233 runtime->buffer_size) 234 dev->adev.hwptr_done_capture -= 235 runtime->buffer_size; 236 237 dev->adev.capture_transfer_done += length; 238 if (dev->adev.capture_transfer_done >= 239 runtime->period_size) { 240 dev->adev.capture_transfer_done -= 241 runtime->period_size; 242 period_elapsed = 1; 243 } 244 snd_pcm_stream_unlock_irqrestore(substream, flags); 245 } 246 if (period_elapsed) 247 snd_pcm_period_elapsed(substream); 248 } 249 urb->status = 0; 250 251 status = usb_submit_urb(urb, GFP_ATOMIC); 252 if (status < 0) { 253 dev_err(dev->dev, 254 "resubmit of audio urb failed (error=%i)\n", 255 status); 256 } 257 return; 258 } 259 260 static int cx231xx_init_audio_isoc(struct cx231xx *dev) 261 { 262 int i, errCode; 263 int sb_size; 264 265 dev_dbg(dev->dev, 266 "%s: Starting ISO AUDIO transfers\n", __func__); 267 268 if (dev->state & DEV_DISCONNECTED) 269 return -ENODEV; 270 271 sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; 272 273 for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { 274 struct urb *urb; 275 int j, k; 276 277 dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); 278 if (!dev->adev.transfer_buffer[i]) 279 return -ENOMEM; 280 281 memset(dev->adev.transfer_buffer[i], 0x80, sb_size); 282 urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC); 283 if (!urb) { 284 for (j = 0; j < i; j++) { 285 usb_free_urb(dev->adev.urb[j]); 286 kfree(dev->adev.transfer_buffer[j]); 287 } 288 return -ENOMEM; 289 } 290 291 urb->dev = dev->udev; 292 urb->context = dev; 293 urb->pipe = usb_rcvisocpipe(dev->udev, 294 dev->adev.end_point_addr); 295 urb->transfer_flags = URB_ISO_ASAP; 296 urb->transfer_buffer = dev->adev.transfer_buffer[i]; 297 urb->interval = 1; 298 urb->complete = cx231xx_audio_isocirq; 299 urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS; 300 urb->transfer_buffer_length = sb_size; 301 302 for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS; 303 j++, k += dev->adev.max_pkt_size) { 304 urb->iso_frame_desc[j].offset = k; 305 urb->iso_frame_desc[j].length = dev->adev.max_pkt_size; 306 } 307 dev->adev.urb[i] = urb; 308 } 309 310 for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { 311 errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); 312 if (errCode < 0) { 313 cx231xx_isoc_audio_deinit(dev); 314 return errCode; 315 } 316 } 317 318 return errCode; 319 } 320 321 static int cx231xx_init_audio_bulk(struct cx231xx *dev) 322 { 323 int i, errCode; 324 int sb_size; 325 326 dev_dbg(dev->dev, 327 "%s: Starting BULK AUDIO transfers\n", __func__); 328 329 if (dev->state & DEV_DISCONNECTED) 330 return -ENODEV; 331 332 sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; 333 334 for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { 335 struct urb *urb; 336 int j; 337 338 dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); 339 if (!dev->adev.transfer_buffer[i]) 340 return -ENOMEM; 341 342 memset(dev->adev.transfer_buffer[i], 0x80, sb_size); 343 urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); 344 if (!urb) { 345 for (j = 0; j < i; j++) { 346 usb_free_urb(dev->adev.urb[j]); 347 kfree(dev->adev.transfer_buffer[j]); 348 } 349 return -ENOMEM; 350 } 351 352 urb->dev = dev->udev; 353 urb->context = dev; 354 urb->pipe = usb_rcvbulkpipe(dev->udev, 355 dev->adev.end_point_addr); 356 urb->transfer_flags = 0; 357 urb->transfer_buffer = dev->adev.transfer_buffer[i]; 358 urb->complete = cx231xx_audio_bulkirq; 359 urb->transfer_buffer_length = sb_size; 360 361 dev->adev.urb[i] = urb; 362 363 } 364 365 for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { 366 errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); 367 if (errCode < 0) { 368 cx231xx_bulk_audio_deinit(dev); 369 return errCode; 370 } 371 } 372 373 return errCode; 374 } 375 376 static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, 377 size_t size) 378 { 379 struct snd_pcm_runtime *runtime = subs->runtime; 380 struct cx231xx *dev = snd_pcm_substream_chip(subs); 381 382 dev_dbg(dev->dev, "Allocating vbuffer\n"); 383 if (runtime->dma_area) { 384 if (runtime->dma_bytes > size) 385 return 0; 386 387 vfree(runtime->dma_area); 388 } 389 runtime->dma_area = vmalloc(size); 390 if (!runtime->dma_area) 391 return -ENOMEM; 392 393 runtime->dma_bytes = size; 394 395 return 0; 396 } 397 398 static const struct snd_pcm_hardware snd_cx231xx_hw_capture = { 399 .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | 400 SNDRV_PCM_INFO_MMAP | 401 SNDRV_PCM_INFO_INTERLEAVED | 402 SNDRV_PCM_INFO_MMAP_VALID, 403 404 .formats = SNDRV_PCM_FMTBIT_S16_LE, 405 406 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, 407 408 .rate_min = 48000, 409 .rate_max = 48000, 410 .channels_min = 2, 411 .channels_max = 2, 412 .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ 413 .period_bytes_min = 64, /* 12544/2, */ 414 .period_bytes_max = 12544, 415 .periods_min = 2, 416 .periods_max = 98, /* 12544, */ 417 }; 418 419 static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) 420 { 421 struct cx231xx *dev = snd_pcm_substream_chip(substream); 422 struct snd_pcm_runtime *runtime = substream->runtime; 423 int ret = 0; 424 425 dev_dbg(dev->dev, 426 "opening device and trying to acquire exclusive lock\n"); 427 428 if (dev->state & DEV_DISCONNECTED) { 429 dev_err(dev->dev, 430 "Can't open. the device was removed.\n"); 431 return -ENODEV; 432 } 433 434 /* set alternate setting for audio interface */ 435 /* 1 - 48000 samples per sec */ 436 mutex_lock(&dev->lock); 437 if (dev->USE_ISO) 438 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); 439 else 440 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); 441 mutex_unlock(&dev->lock); 442 if (ret < 0) { 443 dev_err(dev->dev, 444 "failed to set alternate setting !\n"); 445 446 return ret; 447 } 448 449 runtime->hw = snd_cx231xx_hw_capture; 450 451 mutex_lock(&dev->lock); 452 /* inform hardware to start streaming */ 453 ret = cx231xx_capture_start(dev, 1, Audio); 454 455 dev->adev.users++; 456 mutex_unlock(&dev->lock); 457 458 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 459 dev->adev.capture_pcm_substream = substream; 460 runtime->private_data = dev; 461 462 return 0; 463 } 464 465 static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) 466 { 467 int ret; 468 struct cx231xx *dev = snd_pcm_substream_chip(substream); 469 470 dev_dbg(dev->dev, "closing device\n"); 471 472 /* inform hardware to stop streaming */ 473 mutex_lock(&dev->lock); 474 ret = cx231xx_capture_start(dev, 0, Audio); 475 476 /* set alternate setting for audio interface */ 477 /* 1 - 48000 samples per sec */ 478 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); 479 if (ret < 0) { 480 dev_err(dev->dev, 481 "failed to set alternate setting !\n"); 482 483 mutex_unlock(&dev->lock); 484 return ret; 485 } 486 487 dev->adev.users--; 488 if (substream->runtime->dma_area) { 489 dev_dbg(dev->dev, "freeing\n"); 490 vfree(substream->runtime->dma_area); 491 substream->runtime->dma_area = NULL; 492 } 493 mutex_unlock(&dev->lock); 494 495 if (dev->adev.users == 0 && dev->adev.shutdown == 1) { 496 dev_dbg(dev->dev, "audio users: %d\n", dev->adev.users); 497 dev_dbg(dev->dev, "disabling audio stream!\n"); 498 dev->adev.shutdown = 0; 499 dev_dbg(dev->dev, "released lock\n"); 500 if (atomic_read(&dev->stream_started) > 0) { 501 atomic_set(&dev->stream_started, 0); 502 schedule_work(&dev->wq_trigger); 503 } 504 } 505 return 0; 506 } 507 508 static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream, 509 struct snd_pcm_hw_params *hw_params) 510 { 511 struct cx231xx *dev = snd_pcm_substream_chip(substream); 512 int ret; 513 514 dev_dbg(dev->dev, "Setting capture parameters\n"); 515 516 ret = snd_pcm_alloc_vmalloc_buffer(substream, 517 params_buffer_bytes(hw_params)); 518 #if 0 519 /* TODO: set up cx231xx audio chip to deliver the correct audio format, 520 current default is 48000hz multiplexed => 96000hz mono 521 which shouldn't matter since analogue TV only supports mono */ 522 unsigned int channels, rate, format; 523 524 format = params_format(hw_params); 525 rate = params_rate(hw_params); 526 channels = params_channels(hw_params); 527 #endif 528 529 return ret; 530 } 531 532 static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream) 533 { 534 struct cx231xx *dev = snd_pcm_substream_chip(substream); 535 536 dev_dbg(dev->dev, "Stop capture, if needed\n"); 537 538 if (atomic_read(&dev->stream_started) > 0) { 539 atomic_set(&dev->stream_started, 0); 540 schedule_work(&dev->wq_trigger); 541 } 542 543 return 0; 544 } 545 546 static int snd_cx231xx_prepare(struct snd_pcm_substream *substream) 547 { 548 struct cx231xx *dev = snd_pcm_substream_chip(substream); 549 550 dev->adev.hwptr_done_capture = 0; 551 dev->adev.capture_transfer_done = 0; 552 553 return 0; 554 } 555 556 static void audio_trigger(struct work_struct *work) 557 { 558 struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger); 559 560 if (atomic_read(&dev->stream_started)) { 561 dev_dbg(dev->dev, "starting capture"); 562 if (is_fw_load(dev) == 0) 563 cx25840_call(dev, core, load_fw); 564 if (dev->USE_ISO) 565 cx231xx_init_audio_isoc(dev); 566 else 567 cx231xx_init_audio_bulk(dev); 568 } else { 569 dev_dbg(dev->dev, "stopping capture"); 570 cx231xx_isoc_audio_deinit(dev); 571 } 572 } 573 574 static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, 575 int cmd) 576 { 577 struct cx231xx *dev = snd_pcm_substream_chip(substream); 578 int retval = 0; 579 580 if (dev->state & DEV_DISCONNECTED) 581 return -ENODEV; 582 583 spin_lock(&dev->adev.slock); 584 switch (cmd) { 585 case SNDRV_PCM_TRIGGER_START: 586 atomic_set(&dev->stream_started, 1); 587 break; 588 case SNDRV_PCM_TRIGGER_STOP: 589 atomic_set(&dev->stream_started, 0); 590 break; 591 default: 592 retval = -EINVAL; 593 break; 594 } 595 spin_unlock(&dev->adev.slock); 596 597 schedule_work(&dev->wq_trigger); 598 599 return retval; 600 } 601 602 static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream 603 *substream) 604 { 605 struct cx231xx *dev; 606 unsigned long flags; 607 snd_pcm_uframes_t hwptr_done; 608 609 dev = snd_pcm_substream_chip(substream); 610 611 spin_lock_irqsave(&dev->adev.slock, flags); 612 hwptr_done = dev->adev.hwptr_done_capture; 613 spin_unlock_irqrestore(&dev->adev.slock, flags); 614 615 return hwptr_done; 616 } 617 618 static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, 619 unsigned long offset) 620 { 621 void *pageptr = subs->runtime->dma_area + offset; 622 623 return vmalloc_to_page(pageptr); 624 } 625 626 static const struct snd_pcm_ops snd_cx231xx_pcm_capture = { 627 .open = snd_cx231xx_capture_open, 628 .close = snd_cx231xx_pcm_close, 629 .ioctl = snd_pcm_lib_ioctl, 630 .hw_params = snd_cx231xx_hw_capture_params, 631 .hw_free = snd_cx231xx_hw_capture_free, 632 .prepare = snd_cx231xx_prepare, 633 .trigger = snd_cx231xx_capture_trigger, 634 .pointer = snd_cx231xx_capture_pointer, 635 .page = snd_pcm_get_vmalloc_page, 636 }; 637 638 static int cx231xx_audio_init(struct cx231xx *dev) 639 { 640 struct cx231xx_audio *adev = &dev->adev; 641 struct snd_pcm *pcm; 642 struct snd_card *card; 643 static int devnr; 644 int err; 645 struct usb_interface *uif; 646 int i, isoc_pipe = 0; 647 648 if (dev->has_alsa_audio != 1) { 649 /* This device does not support the extension (in this case 650 the device is expecting the snd-usb-audio module or 651 doesn't have analog audio support at all) */ 652 return 0; 653 } 654 655 dev_dbg(dev->dev, 656 "probing for cx231xx non standard usbaudio\n"); 657 658 err = snd_card_new(dev->dev, index[devnr], "Cx231xx Audio", 659 THIS_MODULE, 0, &card); 660 if (err < 0) 661 return err; 662 663 spin_lock_init(&adev->slock); 664 err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm); 665 if (err < 0) 666 goto err_free_card; 667 668 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 669 &snd_cx231xx_pcm_capture); 670 pcm->info_flags = 0; 671 pcm->private_data = dev; 672 strscpy(pcm->name, "Conexant cx231xx Capture", sizeof(pcm->name)); 673 strscpy(card->driver, "Cx231xx-Audio", sizeof(card->driver)); 674 strscpy(card->shortname, "Cx231xx Audio", sizeof(card->shortname)); 675 strscpy(card->longname, "Conexant cx231xx Audio", sizeof(card->longname)); 676 677 INIT_WORK(&dev->wq_trigger, audio_trigger); 678 679 err = snd_card_register(card); 680 if (err < 0) 681 goto err_free_card; 682 683 adev->sndcard = card; 684 adev->udev = dev->udev; 685 686 /* compute alternate max packet sizes for Audio */ 687 uif = 688 dev->udev->actconfig->interface[dev->current_pcb_config. 689 hs_config_info[0].interface_info. 690 audio_index + 1]; 691 692 if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) { 693 err = -ENODEV; 694 goto err_free_card; 695 } 696 697 adev->end_point_addr = 698 uif->altsetting[0].endpoint[isoc_pipe].desc. 699 bEndpointAddress; 700 701 adev->num_alt = uif->num_altsetting; 702 dev_info(dev->dev, 703 "audio EndPoint Addr 0x%x, Alternate settings: %i\n", 704 adev->end_point_addr, adev->num_alt); 705 adev->alt_max_pkt_size = kmalloc_array(32, adev->num_alt, GFP_KERNEL); 706 if (!adev->alt_max_pkt_size) { 707 err = -ENOMEM; 708 goto err_free_card; 709 } 710 711 for (i = 0; i < adev->num_alt; i++) { 712 u16 tmp; 713 714 if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) { 715 err = -ENODEV; 716 goto err_free_pkt_size; 717 } 718 719 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. 720 wMaxPacketSize); 721 adev->alt_max_pkt_size[i] = 722 (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); 723 dev_dbg(dev->dev, 724 "audio alternate setting %i, max size= %i\n", i, 725 adev->alt_max_pkt_size[i]); 726 } 727 728 return 0; 729 730 err_free_pkt_size: 731 kfree(adev->alt_max_pkt_size); 732 err_free_card: 733 snd_card_free(card); 734 735 return err; 736 } 737 738 static int cx231xx_audio_fini(struct cx231xx *dev) 739 { 740 if (dev == NULL) 741 return 0; 742 743 if (dev->has_alsa_audio != 1) { 744 /* This device does not support the extension (in this case 745 the device is expecting the snd-usb-audio module or 746 doesn't have analog audio support at all) */ 747 return 0; 748 } 749 750 if (dev->adev.sndcard) { 751 snd_card_free(dev->adev.sndcard); 752 kfree(dev->adev.alt_max_pkt_size); 753 dev->adev.sndcard = NULL; 754 } 755 756 return 0; 757 } 758 759 static struct cx231xx_ops audio_ops = { 760 .id = CX231XX_AUDIO, 761 .name = "Cx231xx Audio Extension", 762 .init = cx231xx_audio_init, 763 .fini = cx231xx_audio_fini, 764 }; 765 766 static int __init cx231xx_alsa_register(void) 767 { 768 return cx231xx_register_extension(&audio_ops); 769 } 770 771 static void __exit cx231xx_alsa_unregister(void) 772 { 773 cx231xx_unregister_extension(&audio_ops); 774 } 775 776 MODULE_LICENSE("GPL"); 777 MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>"); 778 MODULE_DESCRIPTION("Cx231xx Audio driver"); 779 780 module_init(cx231xx_alsa_register); 781 module_exit(cx231xx_alsa_unregister); 782