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

📄 maestro.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
		unsigned x = bsize - bptr;		memset(buf + bptr, c, x);		/* account for wrapping? */		bptr = 0;		len -= x;	}	memset(buf + bptr, c, len);}/* call with spinlock held! */static void ess_update_ptr(struct ess_state *s){	unsigned hwptr;	int diff;	/* update ADC pointer */	if (s->dma_adc.ready) {		/* oh boy should this all be re-written.  everything in the current code paths think		that the various counters/pointers are expressed in bytes to the user but we have		two apus doing stereo stuff so we fix it up here.. it propogates to all the various		counters from here.  */		if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {			hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;		} else {			hwptr = get_dmac(s) % s->dma_adc.dmasize;		}		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;		s->dma_adc.hwptr = hwptr;		s->dma_adc.total_bytes += diff;		s->dma_adc.count += diff;		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 			wake_up(&s->dma_adc.wait);		if (!s->dma_adc.mapped) {			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {				/* FILL ME 				wrindir(s, SV_CIENABLE, s->enable); */				stop_adc(s); 				/* brute force everyone back in sync, sigh */				s->dma_adc.count = 0;				s->dma_adc.swptr = 0;				s->dma_adc.hwptr = 0;				s->dma_adc.error++;			}		}	}	/* update DAC pointer */	if (s->dma_dac.ready) {		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 		/* the apu only reports the length it has seen, not the			length of the memory that has been used (the WP			knows that) */		if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))			hwptr<<=1;		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;/*		M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/		s->dma_dac.hwptr = hwptr;		s->dma_dac.total_bytes += diff;		if (s->dma_dac.mapped) {			s->dma_dac.count += diff;			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {				wake_up(&s->dma_dac.wait);			}		} else {			s->dma_dac.count -= diff;/*			M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */			if (s->dma_dac.count <= 0) {				M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, 					hwptr, s->dma_dac.swptr);				/* FILL ME 				wrindir(s, SV_CIENABLE, s->enable); */				/* XXX how on earth can calling this with the lock held work.. */				stop_dac(s);				/* brute force everyone back in sync, sigh */				s->dma_dac.count = 0; 				s->dma_dac.swptr = hwptr; 				s->dma_dac.error++;			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {				clear_advance(s);				s->dma_dac.endcleared = 1;			}			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {				wake_up(&s->dma_dac.wait);/*				printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, 					hwptr);*/			}		}	}}static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs){        struct ess_state *s;        struct ess_card *c = (struct ess_card *)dev_id;	int i;	u32 event;	if ( ! (event = inb(c->iobase+0x1A)) ) return;	outw(inw(c->iobase+4)&1, c->iobase+4);/*	M_printk("maestro int: %x\n",event);*/	if(event&(1<<6))	{		int x;		enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;		int volume;		/* Figure out which volume control button was pushed,		   based on differences from the default register		   values. */		x = inb(c->iobase+0x1c);		if (x&1) vol_evt = MUTE_EVT;		else if (((x>>1)&7) > 4) vol_evt = UP_EVT;		else vol_evt = DOWN_EVT;		/* Reset the volume control registers. */		outb(0x88, c->iobase+0x1c);		outb(0x88, c->iobase+0x1d);		outb(0x88, c->iobase+0x1e);		outb(0x88, c->iobase+0x1f);		/* Deal with the button press in a hammer-handed		   manner by adjusting the master mixer volume. */		volume = c->mix.mixer_state[0] & 0xff;		if (vol_evt == UP_EVT) {			volume += 10;			if (volume > 100)				volume = 100;		}		else if (vol_evt == DOWN_EVT) {			volume -= 10;			if (volume < 0)				volume = 0;		} else {			/* vol_evt == MUTE_EVT */			if (volume == 0)				volume = c->dock_mute_vol;			else {				c->dock_mute_vol = volume;				volume = 0;			}		}		set_mixer (c, 0, (volume << 8) | volume);	}	/* Ack all the interrupts. */	outb(0xFF, c->iobase+0x1A);			/*	 *	Update the pointers for all APU's we are running.	 */	for(i=0;i<NR_DSPS;i++)	{		s=&c->channels[i];		if(s->dev_audio == -1)			break;		spin_lock(&s->lock);		ess_update_ptr(s);		spin_unlock(&s->lock);	}}/* --------------------------------------------------------------------- */static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n";#define VALIDATE_MAGIC(FOO,MAG)                         \({                                                \	if (!(FOO) || (FOO)->magic != MAG) { \		printk(invalid_magic,__FUNCTION__);            \		return -ENXIO;                    \	}                                         \})#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC)#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC)static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ) {	unsigned int left,right;	/* cleanse input a little */	right = ((val >> 8)  & 0xff) ;	left = (val  & 0xff) ;	if(right > 100) right = 100;	if(left > 100) left = 100;	card->mix.mixer_state[mixer]=(right << 8) | left;	card->mix.write_mixer(card,mixer,left,right);}static voidmixer_push_state(struct ess_card *card){	int i;	for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {		if( ! supported_mixer(card,i)) continue;		set_mixer(card,i,card->mix.mixer_state[i]);	}}static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg){	int i, val=0;       unsigned long flags;	VALIDATE_CARD(card);        if (cmd == SOUND_MIXER_INFO) {		mixer_info info;		strncpy(info.id, card_names[card->card_type], sizeof(info.id));		strncpy(info.name,card_names[card->card_type],sizeof(info.name));		info.modify_counter = card->mix.modcnt;		if (copy_to_user((void *)arg, &info, sizeof(info)))			return -EFAULT;		return 0;	}	if (cmd == SOUND_OLD_MIXER_INFO) {		_old_mixer_info info;		strncpy(info.id, card_names[card->card_type], sizeof(info.id));		strncpy(info.name,card_names[card->card_type],sizeof(info.name));		if (copy_to_user((void *)arg, &info, sizeof(info)))			return -EFAULT;		return 0;	}	if (cmd == OSS_GETVERSION)		return put_user(SOUND_VERSION, (int *)arg);	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))                return -EINVAL;        if (_IOC_DIR(cmd) == _IOC_READ) {                switch (_IOC_NR(cmd)) {                case SOUND_MIXER_RECSRC: /* give them the current record source */			if(!card->mix.recmask_io) {				val = 0;			} else {                               spin_lock_irqsave(&card->lock, flags);				val = card->mix.recmask_io(card,1,0);                               spin_unlock_irqrestore(&card->lock, flags);			}			break;			                case SOUND_MIXER_DEVMASK: /* give them the supported mixers */			val = card->mix.supported_mixers;			break;                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */			val = card->mix.record_sources;			break;			                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */			val = card->mix.stereo_mixers;			break;			                case SOUND_MIXER_CAPS:			val = SOUND_CAP_EXCL_INPUT;			break;		default: /* read a specific mixer */			i = _IOC_NR(cmd);			if ( ! supported_mixer(card,i)) 				return -EINVAL;			/* do we ever want to touch the hardware? *//*                     spin_lock_irqsave(&card->lock, flags);			val = card->mix.read_mixer(card,i);                       spin_unlock_irqrestore(&card->lock, flags);*/			val = card->mix.mixer_state[i];/*			M_printk("returned 0x%x for mixer %d\n",val,i);*/			break;		}		return put_user(val,(int *)arg);	}	        if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))		return -EINVAL;		card->mix.modcnt++;	if (get_user(val, (int *)arg))		return -EFAULT;	switch (_IOC_NR(cmd)) {	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */		if (!card->mix.recmask_io) return -EINVAL;		if(!val) return 0;		if(! (val &= card->mix.record_sources)) return -EINVAL;               spin_lock_irqsave(&card->lock, flags);		card->mix.recmask_io(card,0,val);               spin_unlock_irqrestore(&card->lock, flags);		return 0;	default:		i = _IOC_NR(cmd);		if ( ! supported_mixer(card,i)) 			return -EINVAL;               spin_lock_irqsave(&card->lock, flags);		set_mixer(card,i,val);               spin_unlock_irqrestore(&card->lock, flags);		return 0;	}}/* --------------------------------------------------------------------- */static int ess_open_mixdev(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct ess_card *card = NULL;	struct pci_dev *pdev;	struct pci_driver *drvr;	pci_for_each_dev(pdev) {		drvr = pci_dev_driver (pdev);		if (drvr == &maestro_pci_driver) {			card = (struct ess_card*)pci_get_drvdata (pdev);			if (!card)				continue;			if (card->dev_mixer == minor)				break;		}	}	if (!card)		return -ENODEV;	file->private_data = card;	return 0;}static int ess_release_mixdev(struct inode *inode, struct file *file){	struct ess_card *card = (struct ess_card *)file->private_data;	VALIDATE_CARD(card);		return 0;}static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct ess_card *card = (struct ess_card *)file->private_data;	VALIDATE_CARD(card);	return mixer_ioctl(card, cmd, arg);}static /*const*/ struct file_operations ess_mixer_fops = {	owner:		THIS_MODULE,	llseek:         no_llseek,	ioctl:          ess_ioctl_mixdev,	open:           ess_open_mixdev,	release:        ess_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct ess_state *s, int nonblock){	DECLARE_WAITQUEUE(wait,current);	unsigned long flags;	int count;	signed long tmo;	if (s->dma_dac.mapped || !s->dma_dac.ready)		return 0;	current->state = TASK_INTERRUPTIBLE;        add_wait_queue(&s->dma_dac.wait, &wait);        for (;;) {		/* XXX uhm.. questionable locking*/                spin_lock_irqsave(&s->lock, flags);		count = s->dma_dac.count;                spin_unlock_irqrestore(&s->lock, flags);		if (count <= 0)			break;		if (signal_pending(current))                        break;                if (nonblock) {                        remove_wait_queue(&s->dma_dac.wait, &wait);			current->state = TASK_RUNNING;                        return -EBUSY;                }		tmo = (count * HZ) / s->ratedac;		tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];		/* XXX this is just broken.  someone is waking us up alot, or schedule_timeout is broken.			or something.  who cares. - zach */		if (!schedule_timeout(tmo ? tmo : 1) && tmo)			M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies);        }        remove_wait_queue(&s->dma_dac.wait, &wait);	current->state = TASK_RUNNING;        if (signal_pending(current))                return -ERESTARTSYS;        return 0;}/* --------------------------------------------------------------------- *//* Zach sez: "god this is gross.." */static int comb_stereo(unsigned char *real_buffer,unsigned char  *tmp_buffer, int offset, 	int count, int bufsize){  	/* No such thing as stereo recording, so we	use dual input mixers.  which means we have to 	combine mono to stereo buffer.  yuck. 	but we don't have to be able to work a byte at a time..*/	unsigned char *so,*left,*right;	int i;	so = tmp_buffer;	left = real_buffer + offset;	right = real_buffer + bufsize/2 + offset;/*	M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/	for(i=count/4; i ; i--) {		(*(so+2)) = *(right++);		(*(so+3)) = *(right++);		(*so) = *(left++);		(*(so+1)) = *(left++);		so+=4;	}	return 0;}/* in this loop, dma_adc.count signifies the amount of data thats waiting	to be copied to the user's buffer.  it is filled by the interrupt	handler and drained by this loop. */static ssize_t ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct ess_state *s = (struct ess_state *)file->private_data;	ssize_t ret;	unsigned long flags;	unsigned swp

⌨️ 快捷键说明

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