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

📄 usbusx2yaudio.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		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);			usX2Y_clients_stop(usX2Y);		// something is completely wroong > stop evrything		}	}	return err;}/* * return the current pcm pointer.  just return the hwptr_done value. */static snd_pcm_uframes_t snd_usX2Y_pcm_pointer(snd_pcm_substream_t *substream){	snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;	return subs->hwptr_done;}/* * start/stop substream */static int snd_usX2Y_pcm_trigger(snd_pcm_substream_t *substream, int cmd){	snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		snd_printdd("snd_usX2Y_pcm_trigger(START)\n");		if (atomic_read(&subs->state) == state_PREPARED &&		    atomic_read(&subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= state_PREPARED) {			atomic_set(&subs->state, state_PRERUNNING);		} else {			snd_printdd("\n");			return -EPIPE;		}		break;	case SNDRV_PCM_TRIGGER_STOP:		snd_printdd("snd_usX2Y_pcm_trigger(STOP)\n");		if (atomic_read(&subs->state) >= state_PRERUNNING)			atomic_set(&subs->state, state_PREPARED);		break;	default:		return -EINVAL;	}	return 0;}/* * allocate a buffer, setup samplerate * * so far we use a physically linear buffer although packetize transfer * doesn't need a continuous area. * if sg buffer is supported on the later version of alsa, we'll follow * that. */static struct s_c2{	char c1, c2;}	SetRate44100[] ={	{ 0x14, 0x08},	// this line sets 44100, well actually a little less	{ 0x18, 0x40},	// only tascam / frontier design knows the further lines .......	{ 0x18, 0x42},	{ 0x18, 0x45},	{ 0x18, 0x46},	{ 0x18, 0x48},	{ 0x18, 0x4A},	{ 0x18, 0x4C},	{ 0x18, 0x4E},	{ 0x18, 0x50},	{ 0x18, 0x52},	{ 0x18, 0x54},	{ 0x18, 0x56},	{ 0x18, 0x58},	{ 0x18, 0x5A},	{ 0x18, 0x5C},	{ 0x18, 0x5E},	{ 0x18, 0x60},	{ 0x18, 0x62},	{ 0x18, 0x64},	{ 0x18, 0x66},	{ 0x18, 0x68},	{ 0x18, 0x6A},	{ 0x18, 0x6C},	{ 0x18, 0x6E},	{ 0x18, 0x70},	{ 0x18, 0x72},	{ 0x18, 0x74},	{ 0x18, 0x76},	{ 0x18, 0x78},	{ 0x18, 0x7A},	{ 0x18, 0x7C},	{ 0x18, 0x7E}};static struct s_c2 SetRate48000[] ={	{ 0x14, 0x09},	// this line sets 48000, well actually a little less	{ 0x18, 0x40},	// only tascam / frontier design knows the further lines .......	{ 0x18, 0x42},	{ 0x18, 0x45},	{ 0x18, 0x46},	{ 0x18, 0x48},	{ 0x18, 0x4A},	{ 0x18, 0x4C},	{ 0x18, 0x4E},	{ 0x18, 0x50},	{ 0x18, 0x52},	{ 0x18, 0x54},	{ 0x18, 0x56},	{ 0x18, 0x58},	{ 0x18, 0x5A},	{ 0x18, 0x5C},	{ 0x18, 0x5E},	{ 0x18, 0x60},	{ 0x18, 0x62},	{ 0x18, 0x64},	{ 0x18, 0x66},	{ 0x18, 0x68},	{ 0x18, 0x6A},	{ 0x18, 0x6C},	{ 0x18, 0x6E},	{ 0x18, 0x70},	{ 0x18, 0x73},	{ 0x18, 0x74},	{ 0x18, 0x76},	{ 0x18, 0x78},	{ 0x18, 0x7A},	{ 0x18, 0x7C},	{ 0x18, 0x7E}};#define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000)static void i_usX2Y_04Int(struct urb* urb, struct pt_regs *regs){	usX2Ydev_t*	usX2Y = urb->context;		if (urb->status)		snd_printk(KERN_ERR "snd_usX2Y_04Int() urb->status=%i\n", urb->status);	if (0 == --usX2Y->US04->len)		wake_up(&usX2Y->In04WaitQueue);}static int usX2Y_rate_set(usX2Ydev_t *usX2Y, int rate){	int			err = 0, i;	snd_usX2Y_urbSeq_t	*us = NULL;	int			*usbdata = NULL;	struct s_c2		*ra = rate == 48000 ? SetRate48000 : SetRate44100;	if (usX2Y->rate != rate) {		us = kmalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);		if (NULL == us) {			err = -ENOMEM;			goto cleanup;		}		memset(us, 0, sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS); 		usbdata = kmalloc(sizeof(int)*NOOF_SETRATE_URBS, GFP_KERNEL);		if (NULL == usbdata) {			err = -ENOMEM;			goto cleanup;		}		for (i = 0; i < NOOF_SETRATE_URBS; ++i) {			if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {				err = -ENOMEM;				goto cleanup;			}			((char*)(usbdata + i))[0] = ra[i].c1;			((char*)(usbdata + i))[1] = ra[i].c2;			usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4),					  usbdata + i, 2, i_usX2Y_04Int, usX2Y);#ifdef OLD_USB			us->urb[i]->transfer_flags = USB_QUEUE_BULK;#endif		}		us->submitted =	0;		us->len =	NOOF_SETRATE_URBS;		usX2Y->US04 =	us;		wait_event_timeout(usX2Y->In04WaitQueue, 0 == us->len, HZ);		usX2Y->US04 =	NULL;		if (us->len)			err = -ENODEV;	cleanup:		if (us) {			us->submitted =	2*NOOF_SETRATE_URBS;			for (i = 0; i < NOOF_SETRATE_URBS; ++i) {				struct urb *urb = us->urb[i];				if (urb->status) {					if (!err)						err = -ENODEV;					usb_kill_urb(urb);				}				usb_free_urb(urb);			}			usX2Y->US04 = NULL;			kfree(usbdata);			kfree(us);			if (!err) {				usX2Y->rate = rate;			}		}	}	return err;}static int usX2Y_format_set(usX2Ydev_t *usX2Y, snd_pcm_format_t format){	int alternate, err;	struct list_head* p;	if (format == SNDRV_PCM_FORMAT_S24_3LE) {		alternate = 2;		usX2Y->stride = 6;	} else {		alternate = 1;		usX2Y->stride = 4;	}	list_for_each(p, &usX2Y->chip.midi_list) {		snd_usbmidi_input_stop(p);	}	usb_kill_urb(usX2Y->In04urb);	if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) {		snd_printk(KERN_ERR "usb_set_interface error \n");		return err;	}	usX2Y->In04urb->dev = usX2Y->chip.dev;	err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL);	list_for_each(p, &usX2Y->chip.midi_list) {		snd_usbmidi_input_start(p);	}	usX2Y->format = format;	usX2Y->rate = 0;	return err;}static int snd_usX2Y_pcm_hw_params(snd_pcm_substream_t *substream,				   snd_pcm_hw_params_t *hw_params){	int			err = 0;	unsigned int		rate = params_rate(hw_params);	snd_pcm_format_t	format = params_format(hw_params);	snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params);	{	// all pcm substreams off one usX2Y have to operate at the same rate & format		snd_card_t *card = substream->pstr->pcm->card;		struct list_head *list;		list_for_each(list, &card->devices) {			snd_device_t *dev;			snd_pcm_t *pcm;			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 *test_substream;				test_substream = pcm->streams[s].substream;				if (test_substream && test_substream != substream  &&				    test_substream->runtime &&				    ((test_substream->runtime->format &&				      test_substream->runtime->format != format) ||				     (test_substream->runtime->rate &&				      test_substream->runtime->rate != rate)))					return -EINVAL;			}		}	}	if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) {		snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n", substream, params_buffer_bytes(hw_params), err);		return err;	}	return 0;}/* * free the buffer */static int snd_usX2Y_pcm_hw_free(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;	down(&subs->usX2Y->prepare_mutex);	snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {		snd_usX2Y_substream_t *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];		atomic_set(&subs->state, state_STOPPED);		usX2Y_urbs_release(subs);		if (!cap_subs->pcm_substream ||		    !cap_subs->pcm_substream->runtime ||		    !cap_subs->pcm_substream->runtime->status ||		    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {			atomic_set(&cap_subs->state, state_STOPPED);			usX2Y_urbs_release(cap_subs);		}	} else {		snd_usX2Y_substream_t *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];		if (atomic_read(&playback_subs->state) < state_PREPARED) {			atomic_set(&subs->state, state_STOPPED);			usX2Y_urbs_release(subs);		}	}	up(&subs->usX2Y->prepare_mutex);	return snd_pcm_lib_free_pages(substream);}/* * prepare callback * * set format and initialize urbs */static int snd_usX2Y_pcm_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);	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_urbs_start(capsubs)))			goto up_prepare_mutex;	}	if (subs != capsubs && atomic_read(&subs->state) < state_PREPARED)		err = usX2Y_urbs_start(subs); up_prepare_mutex:	up(&usX2Y->prepare_mutex);	return err;}static snd_pcm_hardware_t snd_usX2Y_2c ={	.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 =            2,	.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_pcm_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 = 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_pcm_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;	subs->pcm_substream = NULL;	return err;}static snd_pcm_ops_t snd_usX2Y_pcm_ops = {	.open =		snd_usX2Y_pcm_open,	.close =	snd_usX2Y_pcm_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_usX2Y_pcm_hw_params,	.hw_free =	snd_usX2Y_pcm_hw_free,	.prepare =	snd_usX2Y_pcm_prepare,	.trigger =	snd_usX2Y_pcm_trigger,	.pointer =	snd_usX2Y_pcm_pointer,};/* * free a usb stream instance */static void usX2Y_audio_stream_free(snd_usX2Y_substream_t **usX2Y_substream){	if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) {		kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);		usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;	}	kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]);	usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL;}static void snd_usX2Y_pcm_private_free(snd_pcm_t *pcm){	snd_usX2Y_substream_t **usX2Y_stream = pcm->private_data;	if (usX2Y_stream) {		snd_pcm_lib_preallocate_free_for_all(pcm);		usX2Y_audio_stream_free(usX2Y_stream);	}}static int usX2Y_audio_stream_new(snd_card_t *card, int playback_endpoint, int capture_endpoint){	snd_pcm_t *pcm;	int err, i;	snd_usX2Y_substream_t **usX2Y_substream =		usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs;	for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;	     i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {		usX2Y_substream[i] = kzalloc(sizeof(snd_usX2Y_substream_t), GFP_KERNEL);		if (NULL == usX2Y_substream[i]) {			snd_printk(KERN_ERR "cannot malloc\n");			return -ENOMEM;		}		usX2Y_substream[i]->usX2Y = usX2Y(card);	}	if (playback_endpoint)		usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint;	usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint;	err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs,			  playback_endpoint ? 1 : 0, 1,			  &pcm);	if (err < 0) {		usX2Y_audio_stream_free(usX2Y_substream);		return err;	}	if (playback_endpoint)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_pcm_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_pcm_ops);	pcm->private_data = usX2Y_substream;	pcm->private_free = snd_usX2Y_pcm_private_free;	pcm->info_flags = 0;	sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs);	if ((playback_endpoint &&	     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_pcm_private_free(pcm);		return err;	}	usX2Y(card)->chip.pcm_devs++;	return 0;}/* * create a chip instance and set its names. */int usX2Y_audio_create(snd_card_t* card){	int err = 0;		INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list);	if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8)))		return err;	if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428)	     if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA)))		     return err;	if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122)		err = usX2Y_rate_set(usX2Y(card), 44100);	// Lets us428 recognize output-volume settings, disturbs us122.	return err;}

⌨️ 快捷键说明

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