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

📄 esssolo1.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
		spin_lock_irqsave(&s->lock, flags);		ptr = s->midi.owr;		cnt = MIDIOUTBUF - ptr;		if (s->midi.ocnt + cnt > MIDIOUTBUF)			cnt = MIDIOUTBUF - s->midi.ocnt;		if (cnt <= 0) {			__set_current_state(TASK_INTERRUPTIBLE);			solo1_handle_midi(s);		}		spin_unlock_irqrestore(&s->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			if (file->f_flags & O_NONBLOCK) {				if (!ret)					ret = -EAGAIN;				break;			}			schedule();			if (signal_pending(current)) {				if (!ret)					ret = -ERESTARTSYS;				break;			}			continue;		}		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {			if (!ret)				ret = -EFAULT;			break;		}		ptr = (ptr + cnt) % MIDIOUTBUF;		spin_lock_irqsave(&s->lock, flags);		s->midi.owr = ptr;		s->midi.ocnt += cnt;		spin_unlock_irqrestore(&s->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		spin_lock_irqsave(&s->lock, flags);		solo1_handle_midi(s);		spin_unlock_irqrestore(&s->lock, flags);	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(&s->midi.owait, &wait);	return ret;}/* No kernel lock - we have our own spinlock */static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait){	struct solo1_state *s = (struct solo1_state *)file->private_data;	unsigned long flags;	unsigned int mask = 0;	VALIDATE_STATE(s);	if (file->f_flags & FMODE_WRITE)		poll_wait(file, &s->midi.owait, wait);	if (file->f_flags & FMODE_READ)		poll_wait(file, &s->midi.iwait, wait);	spin_lock_irqsave(&s->lock, flags);	if (file->f_flags & FMODE_READ) {		if (s->midi.icnt > 0)			mask |= POLLIN | POLLRDNORM;	}	if (file->f_flags & FMODE_WRITE) {		if (s->midi.ocnt < MIDIOUTBUF)			mask |= POLLOUT | POLLWRNORM;	}	spin_unlock_irqrestore(&s->lock, flags);	return mask;}static int solo1_midi_open(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	struct list_head *list;	struct solo1_state *s;	for (list = devs.next; ; list = list->next) {		if (list == &devs)			return -ENODEV;		s = list_entry(list, struct solo1_state, devs);		if (s->dev_midi == minor)			break;	}       	VALIDATE_STATE(s);	file->private_data = s;	/* wait for device to become free */	down(&s->open_sem);	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {		if (file->f_flags & O_NONBLOCK) {			up(&s->open_sem);			return -EBUSY;		}		add_wait_queue(&s->open_wait, &wait);		__set_current_state(TASK_INTERRUPTIBLE);		up(&s->open_sem);		schedule();		remove_wait_queue(&s->open_wait, &wait);		set_current_state(TASK_RUNNING);		if (signal_pending(current))			return -ERESTARTSYS;		down(&s->open_sem);	}	spin_lock_irqsave(&s->lock, flags);	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;		outb(0xff, s->mpubase+1); /* reset command */		outb(0x3f, s->mpubase+1); /* uart command */		if (!(inb(s->mpubase+1) & 0x80))			inb(s->mpubase);		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;		outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */		init_timer(&s->midi.timer);		s->midi.timer.expires = jiffies+1;		s->midi.timer.data = (unsigned long)s;		s->midi.timer.function = solo1_midi_timer;		add_timer(&s->midi.timer);	}	if (file->f_mode & FMODE_READ) {		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;	}	if (file->f_mode & FMODE_WRITE) {		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;	}	spin_unlock_irqrestore(&s->lock, flags);	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);	up(&s->open_sem);	return 0;}static int solo1_midi_release(struct inode *inode, struct file *file){	struct solo1_state *s = (struct solo1_state *)file->private_data;	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	unsigned count, tmo;	VALIDATE_STATE(s);	lock_kernel();	if (file->f_mode & FMODE_WRITE) {		add_wait_queue(&s->midi.owait, &wait);		for (;;) {			__set_current_state(TASK_INTERRUPTIBLE);			spin_lock_irqsave(&s->lock, flags);			count = s->midi.ocnt;			spin_unlock_irqrestore(&s->lock, flags);			if (count <= 0)				break;			if (signal_pending(current))				break;			if (file->f_flags & O_NONBLOCK) {				remove_wait_queue(&s->midi.owait, &wait);				set_current_state(TASK_RUNNING);				return -EBUSY;			}			tmo = (count * HZ) / 3100;			if (!schedule_timeout(tmo ? : 1) && tmo)				printk(KERN_DEBUG "solo1: midi timed out??\n");		}		remove_wait_queue(&s->midi.owait, &wait);		set_current_state(TASK_RUNNING);	}	down(&s->open_sem);	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);	spin_lock_irqsave(&s->lock, flags);	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {		outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */		del_timer(&s->midi.timer);			}	spin_unlock_irqrestore(&s->lock, flags);	wake_up(&s->open_wait);	up(&s->open_sem);	unlock_kernel();	return 0;}static /*const*/ struct file_operations solo1_midi_fops = {	owner:		THIS_MODULE,	llseek:		solo1_llseek,	read:		solo1_midi_read,	write:		solo1_midi_write,	poll:		solo1_midi_poll,	open:		solo1_midi_open,	release:	solo1_midi_release,};/* --------------------------------------------------------------------- */static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	static const unsigned char op_offset[18] = {		0x00, 0x01, 0x02, 0x03, 0x04, 0x05,		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,		0x10, 0x11, 0x12, 0x13, 0x14, 0x15	};	struct solo1_state *s = (struct solo1_state *)file->private_data;	struct dm_fm_voice v;	struct dm_fm_note n;	struct dm_fm_params p;	unsigned int io;	unsigned int regb;	switch (cmd) {			case FM_IOCTL_RESET:		for (regb = 0xb0; regb < 0xb9; regb++) {			outb(regb, s->sbbase);			outb(0, s->sbbase+1);			outb(regb, s->sbbase+2);			outb(0, s->sbbase+3);		}		return 0;	case FM_IOCTL_PLAY_NOTE:		if (copy_from_user(&n, (void *)arg, sizeof(n)))			return -EFAULT;		if (n.voice >= 18)			return -EINVAL;		if (n.voice >= 9) {			regb = n.voice - 9;			io = s->sbbase+2;		} else {			regb = n.voice;			io = s->sbbase;		}		outb(0xa0 + regb, io);		outb(n.fnum & 0xff, io+1);		outb(0xb0 + regb, io);		outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);		return 0;	case FM_IOCTL_SET_VOICE:		if (copy_from_user(&v, (void *)arg, sizeof(v)))			return -EFAULT;		if (v.voice >= 18)			return -EINVAL;		regb = op_offset[v.voice];		io = s->sbbase + ((v.op & 1) << 1);		outb(0x20 + regb, io);		outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | 		     ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);		outb(0x40 + regb, io);		outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);		outb(0x60 + regb, io);		outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);		outb(0x80 + regb, io);		outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);		outb(0xe0 + regb, io);		outb(v.waveform & 0x7, io+1);		if (n.voice >= 9) {			regb = n.voice - 9;			io = s->sbbase+2;		} else {			regb = n.voice;			io = s->sbbase;		}		outb(0xc0 + regb, io);		outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |		     (v.connection & 1), io+1);		return 0;			case FM_IOCTL_SET_PARAMS:		if (copy_from_user(&p, (void *)arg, sizeof(p)))			return -EFAULT;		outb(0x08, s->sbbase);		outb((p.kbd_split & 1) << 6, s->sbbase+1);		outb(0xbd, s->sbbase);		outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |		     ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);		return 0;	case FM_IOCTL_SET_OPL:		outb(4, s->sbbase+2);		outb(arg, s->sbbase+3);		return 0;	case FM_IOCTL_SET_MODE:		outb(5, s->sbbase+2);		outb(arg & 1, s->sbbase+3);		return 0;	default:		return -EINVAL;	}}static int solo1_dmfm_open(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	DECLARE_WAITQUEUE(wait, current);	struct list_head *list;	struct solo1_state *s;	for (list = devs.next; ; list = list->next) {		if (list == &devs)			return -ENODEV;		s = list_entry(list, struct solo1_state, devs);		if (s->dev_dmfm == minor)			break;	}       	VALIDATE_STATE(s);	file->private_data = s;	/* wait for device to become free */	down(&s->open_sem);	while (s->open_mode & FMODE_DMFM) {		if (file->f_flags & O_NONBLOCK) {			up(&s->open_sem);			return -EBUSY;		}		add_wait_queue(&s->open_wait, &wait);		__set_current_state(TASK_INTERRUPTIBLE);		up(&s->open_sem);		schedule();		remove_wait_queue(&s->open_wait, &wait);		set_current_state(TASK_RUNNING);		if (signal_pending(current))			return -ERESTARTSYS;		down(&s->open_sem);	}	if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {		up(&s->open_sem);		printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");		return -EBUSY;	}	/* init the stuff */	outb(1, s->sbbase);	outb(0x20, s->sbbase+1); /* enable waveforms */	outb(4, s->sbbase+2);	outb(0, s->sbbase+3);  /* no 4op enabled */	outb(5, s->sbbase+2);	outb(1, s->sbbase+3);  /* enable OPL3 */	s->open_mode |= FMODE_DMFM;	up(&s->open_sem);	return 0;}static int solo1_dmfm_release(struct inode *inode, struct file *file){	struct solo1_state *s = (struct solo1_state *)file->private_data;	unsigned int regb;	VALIDATE_STATE(s);	lock_kernel();	down(&s->open_sem);	s->open_mode &= ~FMODE_DMFM;	for (regb = 0xb0; regb < 0xb9; regb++) {		outb(regb, s->sbbase);		outb(0, s->sbbase+1);		outb(regb, s->sbbase+2);		outb(0, s->sbbase+3);	}	release_region(s->sbbase, FMSYNTH_EXTENT);	wake_up(&s->open_wait);	up(&s->open_sem);	unlock_kernel();	return 0;}static /*const*/ struct file_operations solo1_dmfm_fops = {	owner:		THIS_MODULE,	llseek:		solo1_llseek,	ioctl:		solo1_dmfm_ioctl,	open:		solo1_dmfm_open,	release:	solo1_dmfm_release,};/* --------------------------------------------------------------------- */static struct initvol {	int mixch;	int vol;} initvol[] __initdata = {	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },	{ SOUND_MIXER_WRITE_PCM, 0x4040 },	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },	{ SOUND_MIXER_WRITE_CD, 0x4040 },	{ SOUND_MIXER_WRITE_LINE, 0x4040 },	{ SOUND_MIXER_WRITE_LINE1, 0x4040 },	{ SOUND_MIXER_WRITE_LINE2, 0x4040 },	{ SOUND_MIXER_WRITE_RECLEV, 0x4040 },	{ SOUND_MIXER_WRITE_SPEAKER, 0x4040 },	{ SOUND_MIXER_WRITE_MIC, 0x4040 }};static int setup_solo1(struct solo1_state *s){	struct pci_dev *pcidev = s->dev;	mm_segment_t fs;	int i, val;	/* initialize DDMA base address */	printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);	pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);	/* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */	pci_write_config_dword(pcidev, 0x50, 0);	/* disable legacy audio address decode */	pci_write_config_word(pcidev, 0x40, 0x907f);	/* initialize the chips */	if (!reset_ctrl(s)) {		printk(KERN_ERR "esssolo1: cannot reset controller\n");		return -1;	}	outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */		/* initialize mixer regs */	write_mixer(s, 0x7f, 0); /* disable music digital recording */	write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */	write_mixer(s, 0x64, 0x45); /* volume control */	write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */	write_mixer(s, 0x50, 0);  /* disable spatializer */	write_mixer(s, 0x52, 0);	write_mixer(s, 0x14, 0);  /* DAC1 minimum volume */	write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */	outb(0, s->ddmabase+0xd); /* DMA master clear */	outb(1, s->ddmabase+0xf); /* mask channel */	/*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */	pci_set_master(pcidev);  /* enable bus mastering */		fs = get_fs();	set_fs(KERNEL_DS);	val = SOUND_MASK_LINE;	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);	for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {		val = initvol[i].vol;		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);	}	val = 1; /* enable mic preamp */	mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);	set_fs(fs);	return 0;}static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data){	struct solo1_state *s

⌨️ 快捷键说明

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