684 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Linux driver for TerraTec DMX 6Fire USB4 *5 * PCM driver6 *7 * Author: Torsten Schenk <torsten.schenk@zoho.com>8 * Created: Jan 01, 20119 * Copyright: (C) Torsten Schenk10 */11 12#include "pcm.h"13#include "chip.h"14#include "comm.h"15#include "control.h"16 17enum {18 OUT_N_CHANNELS = 6, IN_N_CHANNELS = 419};20 21/* keep next two synced with22 * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE23 * and CONTROL_RATE_XXX in control.h */24static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };25static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };26static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };27static const int rates_alsaid[] = {28 SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,29 SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,30 SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };31 32enum { /* settings for pcm */33 OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 102434};35 36enum { /* pcm streaming states */37 STREAM_DISABLED, /* no pcm streaming */38 STREAM_STARTING, /* pcm streaming requested, waiting to become ready */39 STREAM_RUNNING, /* pcm streaming running */40 STREAM_STOPPING41};42 43static const struct snd_pcm_hardware pcm_hw = {44 .info = SNDRV_PCM_INFO_MMAP |45 SNDRV_PCM_INFO_INTERLEAVED |46 SNDRV_PCM_INFO_BLOCK_TRANSFER |47 SNDRV_PCM_INFO_MMAP_VALID |48 SNDRV_PCM_INFO_BATCH,49 50 .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,51 52 .rates = SNDRV_PCM_RATE_44100 |53 SNDRV_PCM_RATE_48000 |54 SNDRV_PCM_RATE_88200 |55 SNDRV_PCM_RATE_96000 |56 SNDRV_PCM_RATE_176400 |57 SNDRV_PCM_RATE_192000,58 59 .rate_min = 44100,60 .rate_max = 192000,61 .channels_min = 1,62 .channels_max = 0, /* set in pcm_open, depending on capture/playback */63 .buffer_bytes_max = MAX_BUFSIZE,64 .period_bytes_min = PCM_N_PACKETS_PER_URB * (PCM_MAX_PACKET_SIZE - 4),65 .period_bytes_max = MAX_BUFSIZE,66 .periods_min = 2,67 .periods_max = 102468};69 70static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)71{72 int ret;73 struct control_runtime *ctrl_rt = rt->chip->control;74 75 ctrl_rt->usb_streaming = false;76 ret = ctrl_rt->update_streaming(ctrl_rt);77 if (ret < 0) {78 dev_err(&rt->chip->dev->dev,79 "error stopping streaming while setting samplerate %d.\n",80 rates[rt->rate]);81 return ret;82 }83 84 ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);85 if (ret < 0) {86 dev_err(&rt->chip->dev->dev,87 "error setting samplerate %d.\n",88 rates[rt->rate]);89 return ret;90 }91 92 ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,93 false, false);94 if (ret < 0) {95 dev_err(&rt->chip->dev->dev,96 "error initializing channels while setting samplerate %d.\n",97 rates[rt->rate]);98 return ret;99 }100 101 ctrl_rt->usb_streaming = true;102 ret = ctrl_rt->update_streaming(ctrl_rt);103 if (ret < 0) {104 dev_err(&rt->chip->dev->dev,105 "error starting streaming while setting samplerate %d.\n",106 rates[rt->rate]);107 return ret;108 }109 110 rt->in_n_analog = IN_N_CHANNELS;111 rt->out_n_analog = OUT_N_CHANNELS;112 rt->in_packet_size = rates_in_packet_size[rt->rate];113 rt->out_packet_size = rates_out_packet_size[rt->rate];114 return 0;115}116 117static struct pcm_substream *usb6fire_pcm_get_substream(118 struct snd_pcm_substream *alsa_sub)119{120 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);121 122 if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)123 return &rt->playback;124 else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE)125 return &rt->capture;126 dev_err(&rt->chip->dev->dev, "error getting pcm substream slot.\n");127 return NULL;128}129 130/* call with stream_mutex locked */131static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)132{133 int i;134 struct control_runtime *ctrl_rt = rt->chip->control;135 136 if (rt->stream_state != STREAM_DISABLED) {137 138 rt->stream_state = STREAM_STOPPING;139 140 for (i = 0; i < PCM_N_URBS; i++) {141 usb_kill_urb(&rt->in_urbs[i].instance);142 usb_kill_urb(&rt->out_urbs[i].instance);143 }144 ctrl_rt->usb_streaming = false;145 ctrl_rt->update_streaming(ctrl_rt);146 rt->stream_state = STREAM_DISABLED;147 }148}149 150/* call with stream_mutex locked */151static int usb6fire_pcm_stream_start(struct pcm_runtime *rt)152{153 int ret;154 int i;155 int k;156 struct usb_iso_packet_descriptor *packet;157 158 if (rt->stream_state == STREAM_DISABLED) {159 /* submit our in urbs */160 rt->stream_wait_cond = false;161 rt->stream_state = STREAM_STARTING;162 for (i = 0; i < PCM_N_URBS; i++) {163 for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) {164 packet = &rt->in_urbs[i].packets[k];165 packet->offset = k * rt->in_packet_size;166 packet->length = rt->in_packet_size;167 packet->actual_length = 0;168 packet->status = 0;169 }170 ret = usb_submit_urb(&rt->in_urbs[i].instance,171 GFP_ATOMIC);172 if (ret) {173 usb6fire_pcm_stream_stop(rt);174 return ret;175 }176 }177 178 /* wait for first out urb to return (sent in urb handler) */179 wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,180 HZ);181 if (rt->stream_wait_cond)182 rt->stream_state = STREAM_RUNNING;183 else {184 usb6fire_pcm_stream_stop(rt);185 return -EIO;186 }187 }188 return 0;189}190 191/* call with substream locked */192static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)193{194 int i;195 int frame;196 int frame_count;197 unsigned int total_length = 0;198 struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);199 struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;200 u32 *src = NULL;201 u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off202 * (alsa_rt->frame_bits >> 3));203 u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size204 * (alsa_rt->frame_bits >> 3));205 int bytes_per_frame = alsa_rt->channels << 2;206 207 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {208 /* at least 4 header bytes for valid packet.209 * after that: 32 bits per sample for analog channels */210 if (urb->packets[i].actual_length > 4)211 frame_count = (urb->packets[i].actual_length - 4)212 / (rt->in_n_analog << 2);213 else214 frame_count = 0;215 216 if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)217 src = (u32 *) (urb->buffer + total_length);218 else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)219 src = (u32 *) (urb->buffer - 1 + total_length);220 else221 return;222 src++; /* skip leading 4 bytes of every packet */223 total_length += urb->packets[i].length;224 for (frame = 0; frame < frame_count; frame++) {225 memcpy(dest, src, bytes_per_frame);226 dest += alsa_rt->channels;227 src += rt->in_n_analog;228 sub->dma_off++;229 sub->period_off++;230 if (dest == dest_end) {231 sub->dma_off = 0;232 dest = (u32 *) alsa_rt->dma_area;233 }234 }235 }236}237 238/* call with substream locked */239static void usb6fire_pcm_playback(struct pcm_substream *sub,240 struct pcm_urb *urb)241{242 int i;243 int frame;244 int frame_count;245 struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);246 struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;247 u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off248 * (alsa_rt->frame_bits >> 3));249 u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size250 * (alsa_rt->frame_bits >> 3));251 u32 *dest;252 int bytes_per_frame = alsa_rt->channels << 2;253 254 if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE)255 dest = (u32 *) (urb->buffer - 1);256 else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)257 dest = (u32 *) (urb->buffer);258 else {259 dev_err(&rt->chip->dev->dev, "Unknown sample format.");260 return;261 }262 263 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {264 /* at least 4 header bytes for valid packet.265 * after that: 32 bits per sample for analog channels */266 if (urb->packets[i].length > 4)267 frame_count = (urb->packets[i].length - 4)268 / (rt->out_n_analog << 2);269 else270 frame_count = 0;271 dest++; /* skip leading 4 bytes of every frame */272 for (frame = 0; frame < frame_count; frame++) {273 memcpy(dest, src, bytes_per_frame);274 src += alsa_rt->channels;275 dest += rt->out_n_analog;276 sub->dma_off++;277 sub->period_off++;278 if (src == src_end) {279 src = (u32 *) alsa_rt->dma_area;280 sub->dma_off = 0;281 }282 }283 }284}285 286static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)287{288 struct pcm_urb *in_urb = usb_urb->context;289 struct pcm_urb *out_urb = in_urb->peer;290 struct pcm_runtime *rt = in_urb->chip->pcm;291 struct pcm_substream *sub;292 unsigned long flags;293 int total_length = 0;294 int frame_count;295 int frame;296 int channel;297 int i;298 u8 *dest;299 300 if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING)301 return;302 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)303 if (in_urb->packets[i].status) {304 rt->panic = true;305 return;306 }307 308 if (rt->stream_state == STREAM_DISABLED) {309 dev_err(&rt->chip->dev->dev,310 "internal error: stream disabled in in-urb handler.\n");311 return;312 }313 314 /* receive our capture data */315 sub = &rt->capture;316 spin_lock_irqsave(&sub->lock, flags);317 if (sub->active) {318 usb6fire_pcm_capture(sub, in_urb);319 if (sub->period_off >= sub->instance->runtime->period_size) {320 sub->period_off %= sub->instance->runtime->period_size;321 spin_unlock_irqrestore(&sub->lock, flags);322 snd_pcm_period_elapsed(sub->instance);323 } else324 spin_unlock_irqrestore(&sub->lock, flags);325 } else326 spin_unlock_irqrestore(&sub->lock, flags);327 328 /* setup out urb structure */329 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {330 out_urb->packets[i].offset = total_length;331 out_urb->packets[i].length = (in_urb->packets[i].actual_length332 - 4) / (rt->in_n_analog << 2)333 * (rt->out_n_analog << 2) + 4;334 out_urb->packets[i].status = 0;335 total_length += out_urb->packets[i].length;336 }337 memset(out_urb->buffer, 0, total_length);338 339 /* now send our playback data (if a free out urb was found) */340 sub = &rt->playback;341 spin_lock_irqsave(&sub->lock, flags);342 if (sub->active) {343 usb6fire_pcm_playback(sub, out_urb);344 if (sub->period_off >= sub->instance->runtime->period_size) {345 sub->period_off %= sub->instance->runtime->period_size;346 spin_unlock_irqrestore(&sub->lock, flags);347 snd_pcm_period_elapsed(sub->instance);348 } else349 spin_unlock_irqrestore(&sub->lock, flags);350 } else351 spin_unlock_irqrestore(&sub->lock, flags);352 353 /* setup the 4th byte of each sample (0x40 for analog channels) */354 dest = out_urb->buffer;355 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)356 if (out_urb->packets[i].length >= 4) {357 frame_count = (out_urb->packets[i].length - 4)358 / (rt->out_n_analog << 2);359 *(dest++) = 0xaa;360 *(dest++) = 0xaa;361 *(dest++) = frame_count;362 *(dest++) = 0x00;363 for (frame = 0; frame < frame_count; frame++)364 for (channel = 0;365 channel < rt->out_n_analog;366 channel++) {367 dest += 3; /* skip sample data */368 *(dest++) = 0x40;369 }370 }371 usb_submit_urb(&out_urb->instance, GFP_ATOMIC);372 usb_submit_urb(&in_urb->instance, GFP_ATOMIC);373}374 375static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb)376{377 struct pcm_urb *urb = usb_urb->context;378 struct pcm_runtime *rt = urb->chip->pcm;379 380 if (rt->stream_state == STREAM_STARTING) {381 rt->stream_wait_cond = true;382 wake_up(&rt->stream_wait_queue);383 }384}385 386static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)387{388 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);389 struct pcm_substream *sub = NULL;390 struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;391 392 if (rt->panic)393 return -EPIPE;394 395 mutex_lock(&rt->stream_mutex);396 alsa_rt->hw = pcm_hw;397 398 if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) {399 if (rt->rate < ARRAY_SIZE(rates))400 alsa_rt->hw.rates = rates_alsaid[rt->rate];401 alsa_rt->hw.channels_max = OUT_N_CHANNELS;402 sub = &rt->playback;403 } else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) {404 if (rt->rate < ARRAY_SIZE(rates))405 alsa_rt->hw.rates = rates_alsaid[rt->rate];406 alsa_rt->hw.channels_max = IN_N_CHANNELS;407 sub = &rt->capture;408 }409 410 if (!sub) {411 mutex_unlock(&rt->stream_mutex);412 dev_err(&rt->chip->dev->dev, "invalid stream type.\n");413 return -EINVAL;414 }415 416 sub->instance = alsa_sub;417 sub->active = false;418 mutex_unlock(&rt->stream_mutex);419 return 0;420}421 422static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)423{424 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);425 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);426 unsigned long flags;427 428 if (rt->panic)429 return 0;430 431 mutex_lock(&rt->stream_mutex);432 if (sub) {433 /* deactivate substream */434 spin_lock_irqsave(&sub->lock, flags);435 sub->instance = NULL;436 sub->active = false;437 spin_unlock_irqrestore(&sub->lock, flags);438 439 /* all substreams closed? if so, stop streaming */440 if (!rt->playback.instance && !rt->capture.instance) {441 usb6fire_pcm_stream_stop(rt);442 rt->rate = ARRAY_SIZE(rates);443 }444 }445 mutex_unlock(&rt->stream_mutex);446 return 0;447}448 449static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)450{451 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);452 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);453 struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;454 int ret;455 456 if (rt->panic)457 return -EPIPE;458 if (!sub)459 return -ENODEV;460 461 mutex_lock(&rt->stream_mutex);462 sub->dma_off = 0;463 sub->period_off = 0;464 465 if (rt->stream_state == STREAM_DISABLED) {466 for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++)467 if (alsa_rt->rate == rates[rt->rate])468 break;469 if (rt->rate == ARRAY_SIZE(rates)) {470 mutex_unlock(&rt->stream_mutex);471 dev_err(&rt->chip->dev->dev,472 "invalid rate %d in prepare.\n",473 alsa_rt->rate);474 return -EINVAL;475 }476 477 ret = usb6fire_pcm_set_rate(rt);478 if (ret) {479 mutex_unlock(&rt->stream_mutex);480 return ret;481 }482 ret = usb6fire_pcm_stream_start(rt);483 if (ret) {484 mutex_unlock(&rt->stream_mutex);485 dev_err(&rt->chip->dev->dev,486 "could not start pcm stream.\n");487 return ret;488 }489 }490 mutex_unlock(&rt->stream_mutex);491 return 0;492}493 494static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd)495{496 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);497 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);498 unsigned long flags;499 500 if (rt->panic)501 return -EPIPE;502 if (!sub)503 return -ENODEV;504 505 switch (cmd) {506 case SNDRV_PCM_TRIGGER_START:507 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:508 spin_lock_irqsave(&sub->lock, flags);509 sub->active = true;510 spin_unlock_irqrestore(&sub->lock, flags);511 return 0;512 513 case SNDRV_PCM_TRIGGER_STOP:514 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:515 spin_lock_irqsave(&sub->lock, flags);516 sub->active = false;517 spin_unlock_irqrestore(&sub->lock, flags);518 return 0;519 520 default:521 return -EINVAL;522 }523}524 525static snd_pcm_uframes_t usb6fire_pcm_pointer(526 struct snd_pcm_substream *alsa_sub)527{528 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);529 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);530 unsigned long flags;531 snd_pcm_uframes_t ret;532 533 if (rt->panic || !sub)534 return SNDRV_PCM_POS_XRUN;535 536 spin_lock_irqsave(&sub->lock, flags);537 ret = sub->dma_off;538 spin_unlock_irqrestore(&sub->lock, flags);539 return ret;540}541 542static const struct snd_pcm_ops pcm_ops = {543 .open = usb6fire_pcm_open,544 .close = usb6fire_pcm_close,545 .prepare = usb6fire_pcm_prepare,546 .trigger = usb6fire_pcm_trigger,547 .pointer = usb6fire_pcm_pointer,548};549 550static void usb6fire_pcm_init_urb(struct pcm_urb *urb,551 struct sfire_chip *chip, bool in, int ep,552 void (*handler)(struct urb *))553{554 urb->chip = chip;555 usb_init_urb(&urb->instance);556 urb->instance.transfer_buffer = urb->buffer;557 urb->instance.transfer_buffer_length =558 PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE;559 urb->instance.dev = chip->dev;560 urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep)561 : usb_sndisocpipe(chip->dev, ep);562 urb->instance.interval = 1;563 urb->instance.complete = handler;564 urb->instance.context = urb;565 urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;566}567 568static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt)569{570 int i;571 572 for (i = 0; i < PCM_N_URBS; i++) {573 rt->out_urbs[i].buffer = kcalloc(PCM_MAX_PACKET_SIZE,574 PCM_N_PACKETS_PER_URB,575 GFP_KERNEL);576 if (!rt->out_urbs[i].buffer)577 return -ENOMEM;578 rt->in_urbs[i].buffer = kcalloc(PCM_MAX_PACKET_SIZE,579 PCM_N_PACKETS_PER_URB,580 GFP_KERNEL);581 if (!rt->in_urbs[i].buffer)582 return -ENOMEM;583 }584 return 0;585}586 587static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt)588{589 int i;590 591 for (i = 0; i < PCM_N_URBS; i++) {592 kfree(rt->out_urbs[i].buffer);593 kfree(rt->in_urbs[i].buffer);594 }595}596 597int usb6fire_pcm_init(struct sfire_chip *chip)598{599 int i;600 int ret;601 struct snd_pcm *pcm;602 struct pcm_runtime *rt =603 kzalloc(sizeof(struct pcm_runtime), GFP_KERNEL);604 605 if (!rt)606 return -ENOMEM;607 608 ret = usb6fire_pcm_buffers_init(rt);609 if (ret) {610 usb6fire_pcm_buffers_destroy(rt);611 kfree(rt);612 return ret;613 }614 615 rt->chip = chip;616 rt->stream_state = STREAM_DISABLED;617 rt->rate = ARRAY_SIZE(rates);618 init_waitqueue_head(&rt->stream_wait_queue);619 mutex_init(&rt->stream_mutex);620 621 spin_lock_init(&rt->playback.lock);622 spin_lock_init(&rt->capture.lock);623 624 for (i = 0; i < PCM_N_URBS; i++) {625 usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP,626 usb6fire_pcm_in_urb_handler);627 usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP,628 usb6fire_pcm_out_urb_handler);629 630 rt->in_urbs[i].peer = &rt->out_urbs[i];631 rt->out_urbs[i].peer = &rt->in_urbs[i];632 }633 634 ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);635 if (ret < 0) {636 usb6fire_pcm_buffers_destroy(rt);637 kfree(rt);638 dev_err(&chip->dev->dev, "cannot create pcm instance.\n");639 return ret;640 }641 642 pcm->private_data = rt;643 strcpy(pcm->name, "DMX 6Fire USB");644 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);645 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);646 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);647 648 rt->instance = pcm;649 650 chip->pcm = rt;651 return 0;652}653 654void usb6fire_pcm_abort(struct sfire_chip *chip)655{656 struct pcm_runtime *rt = chip->pcm;657 int i;658 659 if (rt) {660 rt->panic = true;661 662 if (rt->playback.instance)663 snd_pcm_stop_xrun(rt->playback.instance);664 665 if (rt->capture.instance)666 snd_pcm_stop_xrun(rt->capture.instance);667 668 for (i = 0; i < PCM_N_URBS; i++) {669 usb_poison_urb(&rt->in_urbs[i].instance);670 usb_poison_urb(&rt->out_urbs[i].instance);671 }672 673 }674}675 676void usb6fire_pcm_destroy(struct sfire_chip *chip)677{678 struct pcm_runtime *rt = chip->pcm;679 680 usb6fire_pcm_buffers_destroy(rt);681 kfree(rt);682 chip->pcm = NULL;683}684