⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbaudio.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	list_for_each_entry(fp, &subs->fmt_list, list) {		int i;		for (i = 0; i < fp->nr_rates; i++)			subs->rate_list.list[count++] = fp->rate_table[i];	}	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,					 &subs->rate_list);	if (err < 0)		return err;	return 0;}/* * set up the runtime hardware information. */static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs){	struct list_head *p;	int err;	runtime->hw.formats = subs->formats;	runtime->hw.rate_min = 0x7fffffff;	runtime->hw.rate_max = 0;	runtime->hw.channels_min = 256;	runtime->hw.channels_max = 0;	runtime->hw.rates = 0;	/* check min/max rates and channels */	list_for_each(p, &subs->fmt_list) {		struct audioformat *fp;		fp = list_entry(p, struct audioformat, list);		runtime->hw.rates |= fp->rates;		if (runtime->hw.rate_min > fp->rate_min)			runtime->hw.rate_min = fp->rate_min;		if (runtime->hw.rate_max < fp->rate_max)			runtime->hw.rate_max = fp->rate_max;		if (runtime->hw.channels_min > fp->channels)			runtime->hw.channels_min = fp->channels;		if (runtime->hw.channels_max < fp->channels)			runtime->hw.channels_max = fp->channels;		if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) {			/* FIXME: there might be more than one audio formats... */			runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =				fp->frame_size;		}	}	/* set the period time minimum 1ms */	/* FIXME: high-speed mode allows 125us minimum period, but many parts	 * in the current code assume the 1ms period.	 */	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,				     1000 * MIN_PACKS_URB,				     /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);	if (check_hw_params_convention(subs)) {		hwc_debug("setting extra hw constraints...\n");		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,					       hw_rule_rate, subs,					       SNDRV_PCM_HW_PARAM_FORMAT,					       SNDRV_PCM_HW_PARAM_CHANNELS,					       -1)) < 0)			return err;		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,					       hw_rule_channels, subs,					       SNDRV_PCM_HW_PARAM_FORMAT,					       SNDRV_PCM_HW_PARAM_RATE,					       -1)) < 0)			return err;		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,					       hw_rule_format, subs,					       SNDRV_PCM_HW_PARAM_RATE,					       SNDRV_PCM_HW_PARAM_CHANNELS,					       -1)) < 0)			return err;		if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)			return err;	}	return 0;}static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction){	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_usb_substream *subs = &as->substream[direction];	subs->interface = -1;	subs->format = 0;	runtime->hw = snd_usb_hardware;	runtime->private_data = subs;	subs->pcm_substream = substream;	return setup_hw_info(runtime, subs);}static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction){	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);	struct snd_usb_substream *subs = &as->substream[direction];	if (subs->interface >= 0) {		usb_set_interface(subs->dev, subs->interface, 0);		subs->interface = -1;	}	subs->pcm_substream = NULL;	return 0;}static int snd_usb_playback_open(struct snd_pcm_substream *substream){	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK);}static int snd_usb_playback_close(struct snd_pcm_substream *substream){	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK);}static int snd_usb_capture_open(struct snd_pcm_substream *substream){	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE);}static int snd_usb_capture_close(struct snd_pcm_substream *substream){	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);}static struct snd_pcm_ops snd_usb_playback_ops = {	.open =		snd_usb_playback_open,	.close =	snd_usb_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_usb_hw_params,	.hw_free =	snd_usb_hw_free,	.prepare =	snd_usb_pcm_prepare,	.trigger =	snd_usb_pcm_playback_trigger,	.pointer =	snd_usb_pcm_pointer,	.page =		snd_pcm_get_vmalloc_page,};static struct snd_pcm_ops snd_usb_capture_ops = {	.open =		snd_usb_capture_open,	.close =	snd_usb_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_usb_hw_params,	.hw_free =	snd_usb_hw_free,	.prepare =	snd_usb_pcm_prepare,	.trigger =	snd_usb_pcm_capture_trigger,	.pointer =	snd_usb_pcm_pointer,	.page =		snd_pcm_get_vmalloc_page,};/* * helper functions *//* * combine bytes and get an integer value */unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size){	switch (size) {	case 1:  return *bytes;	case 2:  return combine_word(bytes);	case 3:  return combine_triple(bytes);	case 4:  return combine_quad(bytes);	default: return 0;	}}/* * parse descriptor buffer and return the pointer starting the given * descriptor type. */void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype){	u8 *p, *end, *next;	p = descstart;	end = p + desclen;	for (; p < end;) {		if (p[0] < 2)			return NULL;		next = p + p[0];		if (next > end)			return NULL;		if (p[1] == dtype && (!after || (void *)p > after)) {			return p;		}		p = next;	}	return NULL;}/* * find a class-specified interface descriptor with the given subtype. */void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype){	unsigned char *p = after;	while ((p = snd_usb_find_desc(buffer, buflen, p,				      USB_DT_CS_INTERFACE)) != NULL) {		if (p[0] >= 3 && p[2] == dsubtype)			return p;	}	return NULL;}/* * Wrapper for usb_control_msg(). * Allocates a temp buffer to prevent dmaing from/to the stack. */int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,		    __u8 requesttype, __u16 value, __u16 index, void *data,		    __u16 size, int timeout){	int err;	void *buf = NULL;	if (size > 0) {		buf = kmemdup(data, size, GFP_KERNEL);		if (!buf)			return -ENOMEM;	}	err = usb_control_msg(dev, pipe, request, requesttype,			      value, index, buf, size, timeout);	if (size > 0) {		memcpy(data, buf, size);		kfree(buf);	}	return err;}/* * entry point for linux usb interface */static int usb_audio_probe(struct usb_interface *intf,			   const struct usb_device_id *id);static void usb_audio_disconnect(struct usb_interface *intf);static struct usb_device_id usb_audio_ids [] = {#include "usbquirks.h"    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),      .bInterfaceClass = USB_CLASS_AUDIO,      .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL },    { }						/* Terminating entry */};MODULE_DEVICE_TABLE (usb, usb_audio_ids);static struct usb_driver usb_audio_driver = {	.name =		"snd-usb-audio",	.probe =	usb_audio_probe,	.disconnect =	usb_audio_disconnect,	.id_table =	usb_audio_ids,};#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS)/* * proc interface for list the supported pcm formats */static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer){	struct list_head *p;	static char *sync_types[4] = {		"NONE", "ASYNC", "ADAPTIVE", "SYNC"	};	list_for_each(p, &subs->fmt_list) {		struct audioformat *fp;		fp = list_entry(p, struct audioformat, list);		snd_iprintf(buffer, "  Interface %d\n", fp->iface);		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);		snd_iprintf(buffer, "    Format: 0x%x\n", fp->format);		snd_iprintf(buffer, "    Channels: %d\n", fp->channels);		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",			    fp->endpoint & USB_ENDPOINT_NUMBER_MASK,			    fp->endpoint & USB_DIR_IN ? "IN" : "OUT",			    sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]);		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {			snd_iprintf(buffer, "    Rates: %d - %d (continuous)\n",				    fp->rate_min, fp->rate_max);		} else {			unsigned int i;			snd_iprintf(buffer, "    Rates: ");			for (i = 0; i < fp->nr_rates; i++) {				if (i > 0)					snd_iprintf(buffer, ", ");				snd_iprintf(buffer, "%d", fp->rate_table[i]);			}			snd_iprintf(buffer, "\n");		}		// snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);		// snd_iprintf(buffer, "    EP Attribute = 0x%x\n", fp->attributes);	}}static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer){	if (subs->running) {		unsigned int i;		snd_iprintf(buffer, "  Status: Running\n");		snd_iprintf(buffer, "    Interface = %d\n", subs->interface);		snd_iprintf(buffer, "    Altset = %d\n", subs->format);		snd_iprintf(buffer, "    URBs = %d [ ", subs->nurbs);		for (i = 0; i < subs->nurbs; i++)			snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);		snd_iprintf(buffer, "]\n");		snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize);		snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",			    snd_usb_get_speed(subs->dev) == USB_SPEED_FULL			    ? get_full_speed_hz(subs->freqm)			    : get_high_speed_hz(subs->freqm),			    subs->freqm >> 16, subs->freqm & 0xffff);	} else {		snd_iprintf(buffer, "  Status: Stop\n");	}}static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){	struct snd_usb_stream *stream = entry->private_data;	snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name);	if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) {		snd_iprintf(buffer, "\nPlayback:\n");		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);	}	if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) {		snd_iprintf(buffer, "\nCapture:\n");		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);	}}static void proc_pcm_format_add(struct snd_usb_stream *stream){	struct snd_info_entry *entry;	char name[32];	struct snd_card *card = stream->chip->card;	sprintf(name, "stream%d", stream->pcm_index);	if (! snd_card_proc_new(card, name, &entry))		snd_info_set_text_ops(entry, stream, proc_pcm_format_read);}#elsestatic inline void proc_pcm_format_add(struct snd_usb_stream *stream){}#endif/* * initialize the substream instance. */static void init_substream(struct snd_usb_stream *as, int stream, struct audioformat *fp){	struct snd_usb_substream *subs = &as->substream[stream];	INIT_LIST_HEAD(&subs->fmt_list);	spin_lock_init(&subs->lock);	subs->stream = as;	subs->direction = stream;	subs->dev = as->chip->dev;	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)		subs->ops = audio_urb_ops[stream];	else		subs->ops = audio_urb_ops_high_speed[stream];	snd_pcm_set_ops(as->pcm, stream,			stream == SNDRV_PCM_STREAM_PLAYBACK ?			&snd_usb_playback_ops : &snd_usb_capture_ops);	list_add_tail(&fp->list, &subs->fmt_list);	subs->formats |= 1ULL << fp->format;	subs->endpoint = fp->endpoint;	subs->num_formats++;	subs->fmt_type = fp->fmt_type;}/* * free a substream */static void free_substream(struct snd_usb_substream *subs){	struct list_head *p, *n;	if (! subs->num_formats)		return; /* not initialized */	list_for_each_safe(p, n, &subs->fmt_list) {		struct audioformat *fp = list_entry(p, struct audioformat, list);		kfree(fp->rate_table);		kfree(fp);	}	kfree(subs->rate_list.list);}/* * free a usb stream instance */static void snd_usb_audio_stream_free(struct snd_usb_stream *stream){	free_substream(&stream->substream[0]);	free_substream(&stream->substream[1]);	list_del(&stream->list);	kfree(stream);}static void snd_usb_audio_pcm_free(struct snd_pcm *pcm){	struct snd_usb_stream *stream = pcm->private_data;	if (stream) {		stream->pcm = NULL;		snd_usb_audio_stream_free(stream);	}}/* * add this endpoint to the chip instance. * if a stream with the same endpoint already exists, append to it. * if not, create a new pcm stream. */static int add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp){	struct list_head *p;	struct snd_usb_stream *as;	struct snd_usb_substream *subs;	struct snd_pcm *pcm;	int err;	list_for_each(p, &chip->pcm_list) {		as = list_entry(p, struct snd_usb_stream, list);		if (as->fmt_type != fp->fmt_type)			continue;		subs = &as->substream[stream];	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -