📄 usx2yhwdeppcm.c
字号:
smp_wmb(); // Make shure above modifications are seen by i_usX2Y_subs_startup() usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);}static int usX2Y_usbpcm_urbs_start(snd_usX2Y_substream_t *subs){ int p, u, err, stream = subs->pcm_substream->stream; usX2Ydev_t *usX2Y = subs->usX2Y; if (SNDRV_PCM_STREAM_CAPTURE == stream) { usX2Y->hwdep_pcm_shm->captured_iso_head = -1; usX2Y->hwdep_pcm_shm->captured_iso_frames = 0; } for (p = 0; 3 >= (stream + p); p += 2) { snd_usX2Y_substream_t *subs = usX2Y->subs[stream + p]; if (subs != NULL) { if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0) return err; subs->completed_urb = NULL; } } for (p = 0; p < 4; p++) { snd_usX2Y_substream_t *subs = usX2Y->subs[p]; if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED) goto start; } usX2Y->wait_iso_frame = -1; start: usX2Y_usbpcm_subs_startup(subs); for (u = 0; u < NRURBS; u++) { for (p = 0; 3 >= (stream + p); p += 2) { snd_usX2Y_substream_t *subs = usX2Y->subs[stream + p]; if (subs != NULL) { struct urb *urb = subs->urb[u]; if (usb_pipein(urb->pipe)) { unsigned long pack; if (0 == u) atomic_set(&subs->state, state_STARTING3); urb->dev = usX2Y->chip.dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); urb->iso_frame_desc[pack].length = subs->maxpacksize; } urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) { snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err); err = -EPIPE; goto cleanup; } else { snd_printdd("%i\n", urb->start_frame); if (0 > usX2Y->wait_iso_frame) usX2Y->wait_iso_frame = urb->start_frame; } urb->transfer_flags = 0; } else { atomic_set(&subs->state, state_STARTING1); break; } } } } err = 0; wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs); if (atomic_read(&subs->state) != state_PREPARED) err = -EPIPE; cleanup: if (err) { usX2Y_subs_startup_finish(usX2Y); // Call it now usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything } return err;}/* * prepare callback * * set format and initialize urbs */static int snd_usX2Y_usbpcm_prepare(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data; usX2Ydev_t *usX2Y = subs->usX2Y; snd_usX2Y_substream_t *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]; int err = 0; snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream); if (NULL == usX2Y->hwdep_pcm_shm) { if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(snd_usX2Y_hwdep_pcm_shm_t), GFP_KERNEL))) return -ENOMEM; memset(usX2Y->hwdep_pcm_shm, 0, sizeof(snd_usX2Y_hwdep_pcm_shm_t)); } down(&usX2Y->prepare_mutex); usX2Y_subs_prepare(subs);// Start hardware streams// SyncStream first.... if (atomic_read(&capsubs->state) < state_PREPARED) { if (usX2Y->format != runtime->format) if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0) goto up_prepare_mutex; if (usX2Y->rate != runtime->rate) if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0) goto up_prepare_mutex; snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe"); if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs))) goto up_prepare_mutex; } if (subs != capsubs) { usX2Y->hwdep_pcm_shm->playback_iso_start = -1; if (atomic_read(&subs->state) < state_PREPARED) { while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > usX2Y->hwdep_pcm_shm->captured_iso_frames) { snd_printd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames); if (msleep_interruptible(10)) { err = -ERESTARTSYS; goto up_prepare_mutex; } } if (0 > (err = usX2Y_usbpcm_urbs_start(subs))) goto up_prepare_mutex; } snd_printd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames); } else usX2Y->hwdep_pcm_shm->capture_iso_start = -1; up_prepare_mutex: up(&usX2Y->prepare_mutex); return err;}static snd_pcm_hardware_t snd_usX2Y_4c ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100, .rate_max = 48000, .channels_min = 2, .channels_max = 4, .buffer_bytes_max = (2*128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0};static int snd_usX2Y_usbpcm_open(snd_pcm_substream_t *substream){ snd_usX2Y_substream_t *subs = ((snd_usX2Y_substream_t **) snd_pcm_substream_chip(substream))[substream->stream]; snd_pcm_runtime_t *runtime = substream->runtime; if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS)) return -EBUSY; runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c : (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c); runtime->private_data = subs; subs->pcm_substream = substream; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000); return 0;}static int snd_usX2Y_usbpcm_close(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data; int err = 0; snd_printd("\n"); subs->pcm_substream = NULL; return err;}static snd_pcm_ops_t snd_usX2Y_usbpcm_ops = { .open = snd_usX2Y_usbpcm_open, .close = snd_usX2Y_usbpcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usX2Y_pcm_hw_params, .hw_free = snd_usX2Y_usbpcm_hw_free, .prepare = snd_usX2Y_usbpcm_prepare, .trigger = snd_usX2Y_pcm_trigger, .pointer = snd_usX2Y_pcm_pointer,};static int usX2Y_pcms_lock_check(snd_card_t *card){ struct list_head *list; snd_device_t *dev; snd_pcm_t *pcm; int err = 0; list_for_each(list, &card->devices) { dev = snd_device(list); if (dev->type != SNDRV_DEV_PCM) continue; pcm = dev->device_data; down(&pcm->open_mutex); } list_for_each(list, &card->devices) { int s; dev = snd_device(list); if (dev->type != SNDRV_DEV_PCM) continue; pcm = dev->device_data; for (s = 0; s < 2; ++s) { snd_pcm_substream_t *substream; substream = pcm->streams[s].substream; if (substream && substream->ffile != NULL) err = -EBUSY; } } return err;}static void usX2Y_pcms_unlock(snd_card_t *card){ struct list_head *list; snd_device_t *dev; snd_pcm_t *pcm; list_for_each(list, &card->devices) { dev = snd_device(list); if (dev->type != SNDRV_DEV_PCM) continue; pcm = dev->device_data; up(&pcm->open_mutex); }}static int snd_usX2Y_hwdep_pcm_open(snd_hwdep_t *hw, struct file *file){ // we need to be the first snd_card_t *card = hw->card; int err = usX2Y_pcms_lock_check(card); if (0 == err) usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS; usX2Y_pcms_unlock(card); return err;}static int snd_usX2Y_hwdep_pcm_release(snd_hwdep_t *hw, struct file *file){ snd_card_t *card = hw->card; int err = usX2Y_pcms_lock_check(card); if (0 == err) usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS; usX2Y_pcms_unlock(card); return err;}static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area){}static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area){}static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type){ unsigned long offset; struct page *page; void *vaddr; offset = area->vm_pgoff << PAGE_SHIFT; offset += address - area->vm_start; snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM); vaddr = (char*)((usX2Ydev_t*)area->vm_private_data)->hwdep_pcm_shm + offset; page = virt_to_page(vaddr); get_page(page); if (type) *type = VM_FAULT_MINOR; return page;}static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { .open = snd_usX2Y_hwdep_pcm_vm_open, .close = snd_usX2Y_hwdep_pcm_vm_close, .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,};static int snd_usX2Y_hwdep_pcm_mmap(snd_hwdep_t * hw, struct file *filp, struct vm_area_struct *area){ unsigned long size = (unsigned long)(area->vm_end - area->vm_start); usX2Ydev_t *usX2Y = (usX2Ydev_t*)hw->private_data; if (!(((usX2Ydev_t*)hw->private_data)->chip_status & USX2Y_STAT_CHIP_INIT)) return -EBUSY; /* if userspace tries to mmap beyond end of our buffer, fail */ if (size > PAGE_ALIGN(sizeof(snd_usX2Y_hwdep_pcm_shm_t))) { snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(snd_usX2Y_hwdep_pcm_shm_t)); return -EINVAL; } if (!usX2Y->hwdep_pcm_shm) { return -ENODEV; } area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops; area->vm_flags |= VM_RESERVED; snd_printd("vm_flags=0x%lX\n", area->vm_flags); area->vm_private_data = hw->private_data; return 0;}static void snd_usX2Y_hwdep_pcm_private_free(snd_hwdep_t *hwdep){ usX2Ydev_t *usX2Y = (usX2Ydev_t *)hwdep->private_data; if (NULL != usX2Y->hwdep_pcm_shm) snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));}static void snd_usX2Y_usbpcm_private_free(snd_pcm_t *pcm){ snd_pcm_lib_preallocate_free_for_all(pcm);}int usX2Y_hwdep_pcm_new(snd_card_t* card){ int err; snd_hwdep_t *hw; snd_pcm_t *pcm; struct usb_device *dev = usX2Y(card)->chip.dev; if (1 != nr_of_packs()) return 0; if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0) { snd_printd("\n"); return err; } hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM; hw->private_data = usX2Y(card); hw->private_free = snd_usX2Y_hwdep_pcm_private_free; hw->ops.open = snd_usX2Y_hwdep_pcm_open; hw->ops.release = snd_usX2Y_hwdep_pcm_release; hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap; hw->exclusive = 1; sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum); err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm); if (err < 0) { return err; } snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops); pcm->private_data = usX2Y(card)->subs; pcm->private_free = snd_usX2Y_usbpcm_private_free; pcm->info_flags = 0; sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio"); if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 64*1024, 128*1024)) || 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 64*1024, 128*1024))) { snd_usX2Y_usbpcm_private_free(pcm); return err; } return 0;}#elseint usX2Y_hwdep_pcm_new(snd_card_t* card){ return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -