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

📄 caiaq-audio.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			      const struct urb *urb,			      const struct usb_iso_packet_descriptor *iso){	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;	unsigned char check_byte;	struct snd_pcm_substream *sub;	int stream, i;	spin_lock(&dev->spinlock);		for (i = 0; i < iso->actual_length;) {		if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {			for (stream = 0; 			     stream < dev->n_streams; 			     stream++, i++) {				if (dev->first_packet)					continue;				check_byte = MAKE_CHECKBYTE(dev, stream, i);								if ((usb_buf[i] & 0x3f) != check_byte)					dev->input_panic = 1;				if (usb_buf[i] & 0x80)					dev->output_panic = 1;			}		}		dev->first_packet = 0;		for (stream = 0; stream < dev->n_streams; stream++, i++) {			sub = dev->sub_capture[stream];			if (sub) {				struct snd_pcm_runtime *rt = sub->runtime;				char *audio_buf = rt->dma_area;				int sz = frames_to_bytes(rt, rt->buffer_size);				audio_buf[dev->audio_in_buf_pos[stream]++] =					usb_buf[i];				dev->period_in_count[stream]++;				if (dev->audio_in_buf_pos[stream] == sz)					dev->audio_in_buf_pos[stream] = 0;			}		}	}	spin_unlock(&dev->spinlock);}static void read_in_urb(struct snd_usb_caiaqdev *dev,			const struct urb *urb,			const struct usb_iso_packet_descriptor *iso){	if (!dev->streaming)		return;	switch (dev->spec.data_alignment) {	case 0:		read_in_urb_mode0(dev, urb, iso);		break;	case 2:		read_in_urb_mode2(dev, urb, iso);		break;	}	if (dev->input_panic || dev->output_panic) {		debug("streaming error detected %s %s\n", 				dev->input_panic ? "(input)" : "",				dev->output_panic ? "(output)" : "");	}	check_for_elapsed_periods(dev, dev->sub_capture);}static void fill_out_urb(struct snd_usb_caiaqdev *dev, 			 struct urb *urb, 			 const struct usb_iso_packet_descriptor *iso){	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;	struct snd_pcm_substream *sub;	int stream, i;	spin_lock(&dev->spinlock);		for (i = 0; i < iso->length;) {		for (stream = 0; stream < dev->n_streams; stream++, i++) {			sub = dev->sub_playback[stream];			if (sub) {				struct snd_pcm_runtime *rt = sub->runtime;				char *audio_buf = rt->dma_area;				int sz = frames_to_bytes(rt, rt->buffer_size);				usb_buf[i] =					audio_buf[dev->audio_out_buf_pos[stream]];				dev->period_out_count[stream]++;				dev->audio_out_buf_pos[stream]++;				if (dev->audio_out_buf_pos[stream] == sz)					dev->audio_out_buf_pos[stream] = 0;			} else				usb_buf[i] = 0;		}		/* fill in the check bytes */		if (dev->spec.data_alignment == 2 &&		    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 		    	(dev->n_streams * CHANNELS_PER_STREAM))		    for (stream = 0; stream < dev->n_streams; stream++, i++)		    	usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);	}	spin_unlock(&dev->spinlock);	check_for_elapsed_periods(dev, dev->sub_playback);}static void read_completed(struct urb *urb){	struct snd_usb_caiaq_cb_info *info = urb->context; 	struct snd_usb_caiaqdev *dev;	struct urb *out;	int frame, len, send_it = 0, outframe = 0;	if (urb->status || !info)		return;	dev = info->dev;	if (!dev->streaming)		return;	out = dev->data_urbs_out[info->index];	/* read the recently received packet and send back one which has	 * the same layout */	for (frame = 0; frame < FRAMES_PER_URB; frame++) {		if (urb->iso_frame_desc[frame].status)			continue;		len = urb->iso_frame_desc[outframe].actual_length;		out->iso_frame_desc[outframe].length = len;		out->iso_frame_desc[outframe].actual_length = 0;		out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;				if (len > 0) {			fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);			read_in_urb(dev, urb, &urb->iso_frame_desc[frame]);			send_it = 1;		}		outframe++;	}	if (send_it) {		out->number_of_packets = FRAMES_PER_URB;		out->transfer_flags = URB_ISO_ASAP;		usb_submit_urb(out, GFP_ATOMIC);	}		/* re-submit inbound urb */	for (frame = 0; frame < FRAMES_PER_URB; frame++) {		urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;		urb->iso_frame_desc[frame].length = BYTES_PER_FRAME;		urb->iso_frame_desc[frame].actual_length = 0;	}		urb->number_of_packets = FRAMES_PER_URB;	urb->transfer_flags = URB_ISO_ASAP;	usb_submit_urb(urb, GFP_ATOMIC);}static void write_completed(struct urb *urb){	struct snd_usb_caiaq_cb_info *info = urb->context;	struct snd_usb_caiaqdev *dev = info->dev;	if (!dev->output_running) {		dev->output_running = 1;		wake_up(&dev->prepare_wait_queue);	}}static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret){	int i, frame;	struct urb **urbs;	struct usb_device *usb_dev = dev->chip.dev;	unsigned int pipe;	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? 		usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) :		usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE);	urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL);	if (!urbs) {		log("unable to kmalloc() urbs, OOM!?\n");		*ret = -ENOMEM;		return NULL;	}	for (i = 0; i < N_URBS; i++) {		urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL);		if (!urbs[i]) {			log("unable to usb_alloc_urb(), OOM!?\n");			*ret = -ENOMEM;			return urbs;		}		urbs[i]->transfer_buffer = 			kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL);		if (!urbs[i]->transfer_buffer) {			log("unable to kmalloc() transfer buffer, OOM!?\n");			*ret = -ENOMEM;			return urbs;		}				for (frame = 0; frame < FRAMES_PER_URB; frame++) {			struct usb_iso_packet_descriptor *iso = 				&urbs[i]->iso_frame_desc[frame];						iso->offset = BYTES_PER_FRAME * frame;			iso->length = BYTES_PER_FRAME;		}				urbs[i]->dev = usb_dev;		urbs[i]->pipe = pipe;		urbs[i]->transfer_buffer_length = FRAMES_PER_URB 						* BYTES_PER_FRAME;		urbs[i]->context = &dev->data_cb_info[i];		urbs[i]->interval = 1;		urbs[i]->transfer_flags = URB_ISO_ASAP;		urbs[i]->number_of_packets = FRAMES_PER_URB;		urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ?					read_completed : write_completed;	}	*ret = 0;	return urbs;}static void free_urbs(struct urb **urbs){	int i;	if (!urbs)		return;	for (i = 0; i < N_URBS; i++) {		if (!urbs[i])			continue;				usb_kill_urb(urbs[i]);		kfree(urbs[i]->transfer_buffer);		usb_free_urb(urbs[i]);	}	kfree(urbs);}int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev){	int i, ret;	dev->n_audio_in  = max(dev->spec.num_analog_audio_in, 			       dev->spec.num_digital_audio_in) / 				CHANNELS_PER_STREAM;	dev->n_audio_out = max(dev->spec.num_analog_audio_out,			       dev->spec.num_digital_audio_out) / 				CHANNELS_PER_STREAM;	dev->n_streams = max(dev->n_audio_in, dev->n_audio_out);	debug("dev->n_audio_in = %d\n", dev->n_audio_in);	debug("dev->n_audio_out = %d\n", dev->n_audio_out);	debug("dev->n_streams = %d\n", dev->n_streams);	if (dev->n_streams > MAX_STREAMS) {		log("unable to initialize device, too many streams.\n");		return -EINVAL;	}	ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, 			dev->n_audio_out, dev->n_audio_in, &dev->pcm);	if (ret < 0) {		log("snd_pcm_new() returned %d\n", ret);		return ret;	}	dev->pcm->private_data = dev;	strcpy(dev->pcm->name, dev->product_name);	memset(dev->sub_playback, 0, sizeof(dev->sub_playback));	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));		memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware,			sizeof(snd_usb_caiaq_pcm_hardware));	/* setup samplerates */	dev->samplerates = dev->pcm_info.rates;	switch (dev->chip.usb_id) {	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):		dev->samplerates |= SNDRV_PCM_RATE_88200;		dev->samplerates |= SNDRV_PCM_RATE_192000;		break;	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):		dev->samplerates |= SNDRV_PCM_RATE_88200;		break;	}	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 				&snd_usb_caiaq_ops);	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 				&snd_usb_caiaq_ops);	snd_pcm_lib_preallocate_pages_for_all(dev->pcm,					SNDRV_DMA_TYPE_CONTINUOUS,					snd_dma_continuous_data(GFP_KERNEL),					MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);	dev->data_cb_info =		kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, 					GFP_KERNEL);	if (!dev->data_cb_info)		return -ENOMEM;	for (i = 0; i < N_URBS; i++) {		dev->data_cb_info[i].dev = dev;		dev->data_cb_info[i].index = i;	}		dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret);	if (ret < 0) {		kfree(dev->data_cb_info);		free_urbs(dev->data_urbs_in);		return ret;	}		dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret);	if (ret < 0) {		kfree(dev->data_cb_info);		free_urbs(dev->data_urbs_in);		free_urbs(dev->data_urbs_out);		return ret;	}	return 0;}void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev){	debug("snd_usb_caiaq_audio_free (%p)\n", dev);	stream_stop(dev);	free_urbs(dev->data_urbs_in);	free_urbs(dev->data_urbs_out);	kfree(dev->data_cb_info);}

⌨️ 快捷键说明

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