📄 usbaudio.c
字号:
/* * (Tentative) USB Audio Driver for ALSA * * Main and PCM part * * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> * * Many codes borrowed from audio.c by * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * NOTES: * * - async unlink should be used for avoiding the sleep inside lock. * 2.4.22 usb-uhci seems buggy for async unlinking and results in * oops. in such a cse, pass async_unlink=0 option. * - the linked URBs would be preferred but not used so far because of * the instability of unlinking. * - type II is not supported properly. there is no device which supports * this type *correctly*. SB extigy looks as if it supports, but it's * indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). */#include <sound/driver.h>#include <linux/bitops.h>#include <linux/init.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/usb.h>#include <linux/vmalloc.h>#include <linux/moduleparam.h>#include <linux/mutex.h>#include <sound/core.h>#include <sound/info.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/initval.h>#include "usbaudio.h"MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");MODULE_DESCRIPTION("USB Audio");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */static int nrpacks = 8; /* max. number of packets per urb */static int async_unlink = 1;static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for the USB audio adapter.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable USB audio adapter.");module_param_array(vid, int, NULL, 0444);MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");module_param_array(pid, int, NULL, 0444);MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");module_param(nrpacks, int, 0644);MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");module_param(async_unlink, bool, 0444);MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");module_param_array(device_setup, int, NULL, 0444);MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");/* * debug the h/w constraints *//* #define HW_CONST_DEBUG *//* * */#define MAX_PACKS 20#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */#define MAX_URBS 8#define SYNC_URBS 4 /* always four urbs for sync */#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */struct audioformat { struct list_head list; snd_pcm_format_t format; /* format type */ unsigned int channels; /* # channels */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int frame_size; /* samples per frame for non-audio */ int iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ unsigned char altset_idx; /* array index of altenate setting */ unsigned char attributes; /* corresponding attributes of cs endpoint */ unsigned char endpoint; /* endpoint */ unsigned char ep_attr; /* endpoint attributes */ unsigned int maxpacksize; /* max. packet size */ unsigned int rates; /* rate bitmasks */ unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */};struct snd_usb_substream;struct snd_urb_ctx { struct urb *urb; unsigned int buffer_size; /* size of data buffer, if data URB */ struct snd_usb_substream *subs; int index; /* index for urb array */ int packets; /* number of packets per urb */};struct snd_urb_ops { int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);};struct snd_usb_substream { struct snd_usb_stream *stream; struct usb_device *dev; struct snd_pcm_substream *pcm_substream; int direction; /* playback or capture */ int interface; /* current interface */ int endpoint; /* assigned endpoint */ struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ unsigned int cur_rate; /* current rate (for hw_params callback) */ unsigned int period_bytes; /* current period bytes (for hw_params callback) */ unsigned int format; /* USB data format */ unsigned int datapipe; /* the data i/o pipe */ unsigned int syncpipe; /* 1 - async out or adaptive in */ unsigned int datainterval; /* log_2 of data packet interval */ unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ unsigned int freqmax; /* maximum sampling rate, used for buffer management */ unsigned int phase; /* phase accumulator */ unsigned int maxpacksize; /* max packet size in bytes */ unsigned int maxframesize; /* max packet size in frames */ unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int packs_per_ms; /* packets per millisecond (for playback) */ unsigned int running: 1; /* running status */ unsigned int hwptr_done; /* processed frame position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ unsigned long active_mask; /* bitmask of active urbs */ unsigned long unlink_mask; /* bitmask of unlinked urbs */ unsigned int nurbs; /* # urbs */ struct snd_urb_ctx dataurb[MAX_URBS]; /* data urb table */ struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */ char *syncbuf; /* sync buffer for all sync URBs */ dma_addr_t sync_dma; /* DMA address of syncbuf */ u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ struct list_head fmt_list; /* format list */ struct snd_pcm_hw_constraint_list rate_list; /* limited rates */ spinlock_t lock; struct snd_urb_ops ops; /* callbacks (must be filled at init) */};struct snd_usb_stream { struct snd_usb_audio *chip; struct snd_pcm *pcm; int pcm_index; unsigned int fmt_type; /* USB audio format type (1-3) */ struct snd_usb_substream substream[2]; struct list_head list;};/* * we keep the snd_usb_audio_t instances by ourselves for merging * the all interfaces on the same card as one sound device. */static DEFINE_MUTEX(register_mutex);static struct snd_usb_audio *usb_chip[SNDRV_CARDS];/* * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz */static inline unsigned get_usb_full_speed_rate(unsigned int rate){ return ((rate << 13) + 62) / 125;}/* * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) * this will overflow at approx 4 MHz */static inline unsigned get_usb_high_speed_rate(unsigned int rate){ return ((rate << 10) + 62) / 125;}/* convert our full speed USB rate into sampling rate in Hz */static inline unsigned get_full_speed_hz(unsigned int usb_rate){ return (usb_rate * 125 + (1 << 12)) >> 13;}/* convert our high speed USB rate into sampling rate in Hz */static inline unsigned get_high_speed_hz(unsigned int usb_rate){ return (usb_rate * 125 + (1 << 9)) >> 10;}/* * prepare urb for full speed capture sync pipe * * fill the length and offset of each urb descriptor. * the fixed 10.14 frequency is passed through the pipe. */static int prepare_capture_sync_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ unsigned char *cp = urb->transfer_buffer; struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 3; urb->iso_frame_desc[0].offset = 0; cp[0] = subs->freqn >> 2; cp[1] = subs->freqn >> 10; cp[2] = subs->freqn >> 18; return 0;}/* * prepare urb for high speed capture sync pipe * * fill the length and offset of each urb descriptor. * the fixed 12.13 frequency is passed as 16.16 through the pipe. */static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ unsigned char *cp = urb->transfer_buffer; struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 4; urb->iso_frame_desc[0].offset = 0; cp[0] = subs->freqn; cp[1] = subs->freqn >> 8; cp[2] = subs->freqn >> 16; cp[3] = subs->freqn >> 24; return 0;}/* * process after capture sync complete * - nothing to do */static int retire_capture_sync_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ return 0;}/* * prepare urb for capture data pipe * * fill the offset and length of each descriptor. * * we use a temporary buffer to write the captured data. * since the length of written data is determined by host, we cannot * write onto the pcm buffer directly... the data is thus copied * later at complete callback to the global buffer. */static int prepare_capture_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ int i, offs; struct snd_urb_ctx *ctx = urb->context; offs = 0; urb->dev = ctx->subs->dev; /* we need to set this at each time */ for (i = 0; i < ctx->packets; i++) { urb->iso_frame_desc[i].offset = offs; urb->iso_frame_desc[i].length = subs->curpacksize; offs += subs->curpacksize; } urb->transfer_buffer_length = offs; urb->number_of_packets = ctx->packets; return 0;}/* * process after capture complete * * copy the data from each desctiptor to the pcm buffer, and * update the current position. */static int retire_capture_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ unsigned long flags; unsigned char *cp; int i; unsigned int stride, len, oldptr; int period_elapsed = 0; stride = runtime->frame_bits >> 3; for (i = 0; i < urb->number_of_packets; i++) { cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (urb->iso_frame_desc[i].status) { snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); // continue; } len = urb->iso_frame_desc[i].actual_length / stride; if (! len) continue; /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; subs->hwptr_done += len; if (subs->hwptr_done >= runtime->buffer_size) subs->hwptr_done -= runtime->buffer_size; subs->transfer_done += len; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; period_elapsed = 1; } spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ if (oldptr + len > runtime->buffer_size) { unsigned int cnt = runtime->buffer_size - oldptr; unsigned int blen = cnt * stride; memcpy(runtime->dma_area + oldptr * stride, cp, blen); memcpy(runtime->dma_area, cp + blen, len * stride - blen); } else { memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); } } if (period_elapsed) snd_pcm_period_elapsed(subs->pcm_substream); return 0;}/* * Process after capture complete when paused. Nothing to do. */static int retire_paused_capture_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ return 0;}/* * prepare urb for full speed playback sync pipe * * set up the offset and length to receive the current frequency. */static int prepare_playback_sync_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 3; urb->iso_frame_desc[0].offset = 0; return 0;}/* * prepare urb for high speed playback sync pipe * * set up the offset and length to receive the current frequency. */static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ struct snd_urb_ctx *ctx = urb->context; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->iso_frame_desc[0].length = 4; urb->iso_frame_desc[0].offset = 0; return 0;}/* * process after full speed playback sync complete * * retrieve the current 10.14 frequency from pipe, and set it. * the value is referred in prepare_playback_urb(). */static int retire_playback_sync_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb){ unsigned int f; unsigned long flags; if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 3) { f = combine_triple((u8*)urb->transfer_buffer) << 2; if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { spin_lock_irqsave(&subs->lock, flags); subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } } return 0;}/* * process after high speed playback sync complete
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -